mirror of https://github.com/ghostfolio/ghostfolio
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.
210 lines
5.8 KiB
210 lines
5.8 KiB
import { ImportService } from './import.service';
|
|
|
|
describe('ImportService', () => {
|
|
let importService: ImportService;
|
|
|
|
let exchangeRateDataServiceMock: { toCurrencyAtDate: jest.Mock };
|
|
let dataProviderServiceMock: {
|
|
getDataSourceForImport: jest.Mock;
|
|
getDataSources: jest.Mock;
|
|
getAssetProfiles: jest.Mock;
|
|
};
|
|
let orderServiceMock: { getOrders: jest.Mock };
|
|
let accountServiceMock: { getAccounts: jest.Mock };
|
|
let tagServiceMock: { getTagsForUser: jest.Mock };
|
|
let configurationServiceMock: { get: jest.Mock };
|
|
|
|
beforeEach(() => {
|
|
exchangeRateDataServiceMock = {
|
|
toCurrencyAtDate: jest.fn()
|
|
};
|
|
|
|
dataProviderServiceMock = {
|
|
getDataSourceForImport: jest.fn().mockReturnValue('YAHOO'),
|
|
getDataSources: jest.fn().mockResolvedValue(['MANUAL', 'YAHOO']),
|
|
getAssetProfiles: jest.fn()
|
|
};
|
|
|
|
orderServiceMock = {
|
|
getOrders: jest.fn().mockResolvedValue({ activities: [], count: 0 })
|
|
};
|
|
|
|
accountServiceMock = {
|
|
getAccounts: jest.fn().mockResolvedValue([])
|
|
};
|
|
|
|
tagServiceMock = {
|
|
getTagsForUser: jest.fn().mockResolvedValue([])
|
|
};
|
|
|
|
configurationServiceMock = {
|
|
get: jest.fn().mockImplementation((key: string) => {
|
|
if (key === 'ENABLE_FEATURE_SUBSCRIPTION') {
|
|
return false;
|
|
}
|
|
|
|
if (key === 'MAX_ACTIVITIES_TO_IMPORT') {
|
|
return Number.MAX_SAFE_INTEGER;
|
|
}
|
|
|
|
return undefined;
|
|
})
|
|
};
|
|
|
|
importService = new ImportService(
|
|
accountServiceMock as any,
|
|
null,
|
|
configurationServiceMock as any,
|
|
null,
|
|
dataProviderServiceMock as any,
|
|
exchangeRateDataServiceMock as any,
|
|
null,
|
|
orderServiceMock as any,
|
|
null,
|
|
null,
|
|
null,
|
|
tagServiceMock as any
|
|
);
|
|
});
|
|
|
|
describe('import', () => {
|
|
it('should include valueInBaseCurrency for a dry-run FEE activity', async () => {
|
|
const expectedValueInBaseCurrency = 15;
|
|
|
|
exchangeRateDataServiceMock.toCurrencyAtDate.mockResolvedValue(
|
|
expectedValueInBaseCurrency
|
|
);
|
|
|
|
const activities = await importService.import({
|
|
isDryRun: true,
|
|
maxActivitiesToImport: Number.MAX_SAFE_INTEGER,
|
|
accountsWithBalancesDto: [],
|
|
activitiesDto: [
|
|
{
|
|
currency: 'USD',
|
|
dataSource: 'MANUAL',
|
|
date: '2024-01-15T00:00:00.000Z',
|
|
fee: 0,
|
|
quantity: 1,
|
|
symbol: 'Account Opening Fee',
|
|
type: 'FEE',
|
|
unitPrice: 15
|
|
} as any
|
|
],
|
|
assetProfilesWithMarketDataDto: [],
|
|
tagsDto: [],
|
|
user: {
|
|
id: 'test-user-id',
|
|
settings: { settings: { baseCurrency: 'USD' } }
|
|
} as any
|
|
});
|
|
|
|
expect(activities).toHaveLength(1);
|
|
expect(activities[0].valueInBaseCurrency).toBe(
|
|
expectedValueInBaseCurrency
|
|
);
|
|
expect(activities[0].value).toBe(15);
|
|
expect(exchangeRateDataServiceMock.toCurrencyAtDate).toHaveBeenCalledWith(
|
|
15,
|
|
'USD',
|
|
'USD',
|
|
expect.any(Date)
|
|
);
|
|
});
|
|
|
|
it('should convert valueInBaseCurrency using the correct currencies', async () => {
|
|
exchangeRateDataServiceMock.toCurrencyAtDate.mockResolvedValue(1350.5);
|
|
|
|
dataProviderServiceMock.getAssetProfiles.mockResolvedValue({
|
|
MSFT: {
|
|
currency: 'USD',
|
|
dataSource: 'YAHOO',
|
|
name: 'Microsoft Corporation',
|
|
symbol: 'MSFT'
|
|
}
|
|
});
|
|
|
|
const activities = await importService.import({
|
|
isDryRun: true,
|
|
maxActivitiesToImport: Number.MAX_SAFE_INTEGER,
|
|
accountsWithBalancesDto: [],
|
|
activitiesDto: [
|
|
{
|
|
currency: 'USD',
|
|
dataSource: 'YAHOO',
|
|
date: '2024-01-15T00:00:00.000Z',
|
|
fee: 19,
|
|
quantity: 5,
|
|
symbol: 'MSFT',
|
|
type: 'BUY',
|
|
unitPrice: 298.58
|
|
} as any
|
|
],
|
|
assetProfilesWithMarketDataDto: [],
|
|
tagsDto: [],
|
|
user: {
|
|
id: 'test-user-id',
|
|
settings: { settings: { baseCurrency: 'EUR' } }
|
|
} as any
|
|
});
|
|
|
|
expect(activities).toHaveLength(1);
|
|
expect(activities[0].valueInBaseCurrency).toBe(1350.5);
|
|
expect(activities[0].value).toBeCloseTo(1492.9);
|
|
expect(exchangeRateDataServiceMock.toCurrencyAtDate).toHaveBeenCalledWith(
|
|
expect.closeTo(1492.9),
|
|
'USD',
|
|
'EUR',
|
|
expect.any(Date)
|
|
);
|
|
});
|
|
|
|
it('should fall back to asset profile currency when activity currency is not set', async () => {
|
|
exchangeRateDataServiceMock.toCurrencyAtDate.mockResolvedValue(450);
|
|
|
|
dataProviderServiceMock.getAssetProfiles.mockResolvedValue({
|
|
AAPL: {
|
|
currency: 'EUR',
|
|
dataSource: 'YAHOO',
|
|
name: 'Apple Inc.',
|
|
symbol: 'AAPL'
|
|
}
|
|
});
|
|
|
|
const activities = await importService.import({
|
|
isDryRun: true,
|
|
maxActivitiesToImport: Number.MAX_SAFE_INTEGER,
|
|
accountsWithBalancesDto: [],
|
|
activitiesDto: [
|
|
{
|
|
currency: undefined,
|
|
dataSource: 'YAHOO',
|
|
date: '2024-06-01T00:00:00.000Z',
|
|
fee: 0,
|
|
quantity: 2,
|
|
symbol: 'AAPL',
|
|
type: 'BUY',
|
|
unitPrice: 250
|
|
} as any
|
|
],
|
|
assetProfilesWithMarketDataDto: [],
|
|
tagsDto: [],
|
|
user: {
|
|
id: 'test-user-id',
|
|
settings: { settings: { baseCurrency: 'CHF' } }
|
|
} as any
|
|
});
|
|
|
|
expect(activities).toHaveLength(1);
|
|
expect(activities[0].valueInBaseCurrency).toBe(450);
|
|
|
|
// Should fall back to asset profile currency (EUR) when activity currency is undefined
|
|
expect(exchangeRateDataServiceMock.toCurrencyAtDate).toHaveBeenCalledWith(
|
|
500,
|
|
'EUR',
|
|
'CHF',
|
|
expect.any(Date)
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|