Feature/Set up unit test that loads activity from exported json file (#3901)

* Set up unit test that loads activity from exported json file

* Update changelog
pull/3910/head
Dhaneshwari Tendle 2 weeks ago committed by GitHub
parent d158d0c326
commit 7a11bb93d5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added the name to the tooltip of the chart of the holdings tab on the home page (experimental) - Added the name to the tooltip of the chart of the holdings tab on the home page (experimental)
### Changed
- Improved the portfolio unit tests to work with exported activity files
### Fixed ### Fixed
- Considered the language of the user settings on login with _Security Token_ - Considered the language of the user settings on login with _Security Token_

@ -1,3 +1,5 @@
import { readFileSync } from 'fs';
export const activityDummyData = { export const activityDummyData = {
accountId: undefined, accountId: undefined,
accountUserId: undefined, accountUserId: undefined,
@ -29,3 +31,7 @@ export const symbolProfileDummyData = {
export const userDummyData = { export const userDummyData = {
id: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' id: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
}; };
export function loadActivityExportFile(filePath: string) {
return JSON.parse(readFileSync(filePath, 'utf8')).activities;
}

@ -1,259 +1,253 @@
import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface'; import { CreateOrderDto } from '@ghostfolio/api/app/order/create-order.dto';
import { import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface';
activityDummyData, import {
symbolProfileDummyData, activityDummyData,
userDummyData loadActivityExportFile,
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils'; symbolProfileDummyData,
import { userDummyData
PerformanceCalculationType, } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils';
PortfolioCalculatorFactory import {
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory'; PerformanceCalculationType,
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service'; PortfolioCalculatorFactory
import { CurrentRateServiceMock } from '@ghostfolio/api/app/portfolio/current-rate.service.mock'; } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service'; import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
import { RedisCacheServiceMock } from '@ghostfolio/api/app/redis-cache/redis-cache.service.mock'; import { CurrentRateServiceMock } from '@ghostfolio/api/app/portfolio/current-rate.service.mock';
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { RedisCacheServiceMock } from '@ghostfolio/api/app/redis-cache/redis-cache.service.mock';
import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { parseDate } from '@ghostfolio/common/helper'; import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service';
import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock';
import { Big } from 'big.js'; import { parseDate } from '@ghostfolio/common/helper';
import { last } from 'lodash';
import { Big } from 'big.js';
jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { import { last } from 'lodash';
return { import { join } from 'path';
// eslint-disable-next-line @typescript-eslint/naming-convention
CurrentRateService: jest.fn().mockImplementation(() => { jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => {
return CurrentRateServiceMock; return {
}) // eslint-disable-next-line @typescript-eslint/naming-convention
}; CurrentRateService: jest.fn().mockImplementation(() => {
}); return CurrentRateServiceMock;
})
jest.mock( };
'@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service', });
() => {
return { jest.mock(
// eslint-disable-next-line @typescript-eslint/naming-convention '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service',
PortfolioSnapshotService: jest.fn().mockImplementation(() => { () => {
return PortfolioSnapshotServiceMock; return {
}) // eslint-disable-next-line @typescript-eslint/naming-convention
}; PortfolioSnapshotService: jest.fn().mockImplementation(() => {
} return PortfolioSnapshotServiceMock;
); })
};
jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => { }
return { );
// eslint-disable-next-line @typescript-eslint/naming-convention
RedisCacheService: jest.fn().mockImplementation(() => { jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => {
return RedisCacheServiceMock; return {
}) // eslint-disable-next-line @typescript-eslint/naming-convention
}; RedisCacheService: jest.fn().mockImplementation(() => {
}); return RedisCacheServiceMock;
})
describe('PortfolioCalculator', () => { };
let configurationService: ConfigurationService; });
let currentRateService: CurrentRateService;
let exchangeRateDataService: ExchangeRateDataService; describe('PortfolioCalculator', () => {
let portfolioCalculatorFactory: PortfolioCalculatorFactory; let activityDtos: CreateOrderDto[];
let portfolioSnapshotService: PortfolioSnapshotService;
let redisCacheService: RedisCacheService; let configurationService: ConfigurationService;
let currentRateService: CurrentRateService;
beforeEach(() => { let exchangeRateDataService: ExchangeRateDataService;
configurationService = new ConfigurationService(); let portfolioCalculatorFactory: PortfolioCalculatorFactory;
let portfolioSnapshotService: PortfolioSnapshotService;
currentRateService = new CurrentRateService(null, null, null, null); let redisCacheService: RedisCacheService;
exchangeRateDataService = new ExchangeRateDataService( beforeAll(() => {
null, activityDtos = loadActivityExportFile(
null, join(
null, __dirname,
null '../../../../../../../test/import/ok-novn-buy-and-sell.json'
); )
);
portfolioSnapshotService = new PortfolioSnapshotService(null); });
redisCacheService = new RedisCacheService(null, null); beforeEach(() => {
configurationService = new ConfigurationService();
portfolioCalculatorFactory = new PortfolioCalculatorFactory(
configurationService, currentRateService = new CurrentRateService(null, null, null, null);
currentRateService,
exchangeRateDataService, exchangeRateDataService = new ExchangeRateDataService(
portfolioSnapshotService, null,
redisCacheService null,
); null,
}); null
);
describe('get current positions', () => {
it.only('with NOVN.SW buy and sell', async () => { portfolioSnapshotService = new PortfolioSnapshotService(null);
jest.useFakeTimers().setSystemTime(parseDate('2022-04-11').getTime());
redisCacheService = new RedisCacheService(null, null);
const activities: Activity[] = [
{ portfolioCalculatorFactory = new PortfolioCalculatorFactory(
...activityDummyData, configurationService,
date: new Date('2022-03-07'), currentRateService,
fee: 0, exchangeRateDataService,
quantity: 2, portfolioSnapshotService,
SymbolProfile: { redisCacheService
...symbolProfileDummyData, );
currency: 'CHF', });
dataSource: 'YAHOO',
name: 'Novartis AG', describe('get current positions', () => {
symbol: 'NOVN.SW' it.only('with NOVN.SW buy and sell', async () => {
}, jest.useFakeTimers().setSystemTime(parseDate('2022-04-11').getTime());
type: 'BUY',
unitPrice: 75.8 const activities: Activity[] = activityDtos.map((activity) => ({
}, ...activityDummyData,
{ ...activity,
...activityDummyData, date: parseDate(activity.date),
date: new Date('2022-04-08'), SymbolProfile: {
fee: 0, ...symbolProfileDummyData,
quantity: 2, currency: activity.currency,
SymbolProfile: { dataSource: activity.dataSource,
...symbolProfileDummyData, name: 'Novartis AG',
currency: 'CHF', symbol: activity.symbol
dataSource: 'YAHOO', }
name: 'Novartis AG', }));
symbol: 'NOVN.SW'
}, const portfolioCalculator = portfolioCalculatorFactory.createCalculator({
type: 'SELL', activities,
unitPrice: 85.73 calculationType: PerformanceCalculationType.TWR,
} currency: 'CHF',
]; userId: userDummyData.id
});
const portfolioCalculator = portfolioCalculatorFactory.createCalculator({
activities, const portfolioSnapshot = await portfolioCalculator.computeSnapshot();
calculationType: PerformanceCalculationType.TWR,
currency: 'CHF', const investments = portfolioCalculator.getInvestments();
userId: userDummyData.id
}); const investmentsByMonth = portfolioCalculator.getInvestmentsByGroup({
data: portfolioSnapshot.historicalData,
const portfolioSnapshot = await portfolioCalculator.computeSnapshot(); groupBy: 'month'
});
const investments = portfolioCalculator.getInvestments();
expect(portfolioSnapshot.historicalData[0]).toEqual({
const investmentsByMonth = portfolioCalculator.getInvestmentsByGroup({ date: '2022-03-06',
data: portfolioSnapshot.historicalData, investmentValueWithCurrencyEffect: 0,
groupBy: 'month' netPerformance: 0,
}); netPerformanceInPercentage: 0,
netPerformanceInPercentageWithCurrencyEffect: 0,
expect(portfolioSnapshot.historicalData[0]).toEqual({ netPerformanceWithCurrencyEffect: 0,
date: '2022-03-06', netWorth: 0,
investmentValueWithCurrencyEffect: 0, totalAccountBalance: 0,
netPerformance: 0, totalInvestment: 0,
netPerformanceInPercentage: 0, totalInvestmentValueWithCurrencyEffect: 0,
netPerformanceInPercentageWithCurrencyEffect: 0, value: 0,
netPerformanceWithCurrencyEffect: 0, valueWithCurrencyEffect: 0
netWorth: 0, });
totalAccountBalance: 0,
totalInvestment: 0, expect(portfolioSnapshot.historicalData[1]).toEqual({
totalInvestmentValueWithCurrencyEffect: 0, date: '2022-03-07',
value: 0, investmentValueWithCurrencyEffect: 151.6,
valueWithCurrencyEffect: 0 netPerformance: 0,
}); netPerformanceInPercentage: 0,
netPerformanceInPercentageWithCurrencyEffect: 0,
expect(portfolioSnapshot.historicalData[1]).toEqual({ netPerformanceWithCurrencyEffect: 0,
date: '2022-03-07', netWorth: 151.6,
investmentValueWithCurrencyEffect: 151.6, totalAccountBalance: 0,
netPerformance: 0, totalInvestment: 151.6,
netPerformanceInPercentage: 0, totalInvestmentValueWithCurrencyEffect: 151.6,
netPerformanceInPercentageWithCurrencyEffect: 0, value: 151.6,
netPerformanceWithCurrencyEffect: 0, valueWithCurrencyEffect: 151.6
netWorth: 151.6, });
totalAccountBalance: 0,
totalInvestment: 151.6, expect(
totalInvestmentValueWithCurrencyEffect: 151.6, portfolioSnapshot.historicalData[
value: 151.6, portfolioSnapshot.historicalData.length - 1
valueWithCurrencyEffect: 151.6 ]
}); ).toEqual({
date: '2022-04-11',
expect( investmentValueWithCurrencyEffect: 0,
portfolioSnapshot.historicalData[ netPerformance: 19.86,
portfolioSnapshot.historicalData.length - 1 netPerformanceInPercentage: 0.13100263852242744,
] netPerformanceInPercentageWithCurrencyEffect: 0.13100263852242744,
).toEqual({ netPerformanceWithCurrencyEffect: 19.86,
date: '2022-04-11', netWorth: 0,
investmentValueWithCurrencyEffect: 0, totalAccountBalance: 0,
netPerformance: 19.86, totalInvestment: 0,
netPerformanceInPercentage: 0.13100263852242744, totalInvestmentValueWithCurrencyEffect: 0,
netPerformanceInPercentageWithCurrencyEffect: 0.13100263852242744, value: 0,
netPerformanceWithCurrencyEffect: 19.86, valueWithCurrencyEffect: 0
netWorth: 0, });
totalAccountBalance: 0,
totalInvestment: 0, expect(portfolioSnapshot).toMatchObject({
totalInvestmentValueWithCurrencyEffect: 0, currentValueInBaseCurrency: new Big('0'),
value: 0, errors: [],
valueWithCurrencyEffect: 0 hasErrors: false,
}); positions: [
{
expect(portfolioSnapshot).toMatchObject({ averagePrice: new Big('0'),
currentValueInBaseCurrency: new Big('0'), currency: 'CHF',
errors: [], dataSource: 'YAHOO',
hasErrors: false, dividend: new Big('0'),
positions: [ dividendInBaseCurrency: new Big('0'),
{ fee: new Big('0'),
averagePrice: new Big('0'), feeInBaseCurrency: new Big('0'),
currency: 'CHF', firstBuyDate: '2022-03-07',
dataSource: 'YAHOO', grossPerformance: new Big('19.86'),
dividend: new Big('0'), grossPerformancePercentage: new Big('0.13100263852242744063'),
dividendInBaseCurrency: new Big('0'), grossPerformancePercentageWithCurrencyEffect: new Big(
fee: new Big('0'), '0.13100263852242744063'
feeInBaseCurrency: new Big('0'), ),
firstBuyDate: '2022-03-07', grossPerformanceWithCurrencyEffect: new Big('19.86'),
grossPerformance: new Big('19.86'), investment: new Big('0'),
grossPerformancePercentage: new Big('0.13100263852242744063'), investmentWithCurrencyEffect: new Big('0'),
grossPerformancePercentageWithCurrencyEffect: new Big( netPerformance: new Big('19.86'),
'0.13100263852242744063' netPerformancePercentage: new Big('0.13100263852242744063'),
), netPerformancePercentageWithCurrencyEffectMap: {
grossPerformanceWithCurrencyEffect: new Big('19.86'), max: new Big('0.13100263852242744063')
investment: new Big('0'), },
investmentWithCurrencyEffect: new Big('0'), netPerformanceWithCurrencyEffectMap: {
netPerformance: new Big('19.86'), max: new Big('19.86')
netPerformancePercentage: new Big('0.13100263852242744063'), },
netPerformancePercentageWithCurrencyEffectMap: { marketPrice: 87.8,
max: new Big('0.13100263852242744063') marketPriceInBaseCurrency: 87.8,
}, quantity: new Big('0'),
netPerformanceWithCurrencyEffectMap: { symbol: 'NOVN.SW',
max: new Big('19.86') tags: [],
}, timeWeightedInvestment: new Big('151.6'),
marketPrice: 87.8, timeWeightedInvestmentWithCurrencyEffect: new Big('151.6'),
marketPriceInBaseCurrency: 87.8, transactionCount: 2,
quantity: new Big('0'), valueInBaseCurrency: new Big('0')
symbol: 'NOVN.SW', }
tags: [], ],
timeWeightedInvestment: new Big('151.6'), totalFeesWithCurrencyEffect: new Big('0'),
timeWeightedInvestmentWithCurrencyEffect: new Big('151.6'), totalInterestWithCurrencyEffect: new Big('0'),
transactionCount: 2, totalInvestment: new Big('0'),
valueInBaseCurrency: new Big('0') totalInvestmentWithCurrencyEffect: new Big('0'),
} totalLiabilitiesWithCurrencyEffect: new Big('0'),
], totalValuablesWithCurrencyEffect: new Big('0')
totalFeesWithCurrencyEffect: new Big('0'), });
totalInterestWithCurrencyEffect: new Big('0'),
totalInvestment: new Big('0'), expect(last(portfolioSnapshot.historicalData)).toMatchObject(
totalInvestmentWithCurrencyEffect: new Big('0'), expect.objectContaining({
totalLiabilitiesWithCurrencyEffect: new Big('0'), netPerformance: 19.86,
totalValuablesWithCurrencyEffect: new Big('0') netPerformanceInPercentage: 0.13100263852242744063,
}); netPerformanceInPercentageWithCurrencyEffect: 0.13100263852242744063,
netPerformanceWithCurrencyEffect: 19.86,
expect(last(portfolioSnapshot.historicalData)).toMatchObject( totalInvestmentValueWithCurrencyEffect: 0
expect.objectContaining({ })
netPerformance: 19.86, );
netPerformanceInPercentage: 0.13100263852242744063,
netPerformanceInPercentageWithCurrencyEffect: 0.13100263852242744063, expect(investments).toEqual([
netPerformanceWithCurrencyEffect: 19.86, { date: '2022-03-07', investment: new Big('151.6') },
totalInvestmentValueWithCurrencyEffect: 0 { date: '2022-04-08', investment: new Big('0') }
}) ]);
);
expect(investmentsByMonth).toEqual([
expect(investments).toEqual([ { date: '2022-03-01', investment: 151.6 },
{ date: '2022-03-07', investment: new Big('151.6') }, { date: '2022-04-01', investment: -151.6 }
{ date: '2022-04-08', investment: new Big('0') } ]);
]); });
});
expect(investmentsByMonth).toEqual([ });
{ date: '2022-03-01', investment: 151.6 },
{ date: '2022-04-01', investment: -151.6 }
]);
});
});
});

@ -11,7 +11,7 @@
"unitPrice": 85.73, "unitPrice": 85.73,
"currency": "CHF", "currency": "CHF",
"dataSource": "YAHOO", "dataSource": "YAHOO",
"date": "2022-04-07T22:00:00.000Z", "date": "2022-04-08T00:00:00.000Z",
"symbol": "NOVN.SW" "symbol": "NOVN.SW"
}, },
{ {
@ -21,7 +21,7 @@
"unitPrice": 75.8, "unitPrice": 75.8,
"currency": "CHF", "currency": "CHF",
"dataSource": "YAHOO", "dataSource": "YAHOO",
"date": "2022-03-06T23:00:00.000Z", "date": "2022-03-07T00:00:00.000Z",
"symbol": "NOVN.SW" "symbol": "NOVN.SW"
} }
] ]

Loading…
Cancel
Save