@yoroi/portfolio
Version:
The Portfolio package of Yoroi SDK
545 lines • 18.3 kB
JavaScript
import { Api, Chain, Portfolio } from '@yoroi/types';
import { apiConfig, portfolioApiMaker } from './api-maker';
import { tokenDiscoveryMocks } from '../token-discovery.mocks';
import { tokenMocks } from '../token.mocks';
import { tokenActivityMocks } from '../token-activity.mocks';
import { tokenImageInvalidateMocks } from '../token-image-invalidate.mocks';
import { tokenHistoryMocks } from '../token-history.mocks';
describe('portfolioApiMaker', () => {
const mockNetwork = Chain.Network.Mainnet;
const mockRequest = jest.fn();
beforeEach(() => {
jest.resetAllMocks();
});
it('should return a PortfolioApi object', () => {
const api = portfolioApiMaker({
network: mockNetwork,
request: mockRequest,
maxIdsPerRequest: 10,
maxConcurrentRequests: 10
});
expect(Object.isFrozen(api)).toBe(true);
expect(api).toBeDefined();
expect(api).toHaveProperty('tokenDiscovery');
expect(api).toHaveProperty('tokenInfos');
expect(api).toHaveProperty('tokenTraits');
expect(api).toHaveProperty('tokenActivity');
expect(api).toHaveProperty('tokenHistory');
expect(api).toHaveProperty('tokenImageInvalidate');
});
it('should return a PortfolioApi object with default fetchData (coverage)', () => {
const api = portfolioApiMaker({
network: mockNetwork,
maxIdsPerRequest: 10,
maxConcurrentRequests: 10
});
expect(api).toBeDefined();
expect(api).toHaveProperty('tokenDiscovery');
expect(api).toHaveProperty('tokenInfos');
expect(api).toHaveProperty('tokenTraits');
expect(api).toHaveProperty('tokenActivity');
expect(api).toHaveProperty('tokenHistory');
expect(api).toHaveProperty('tokenImageInvalidate');
});
it('should call the fetchData function with the correct arguments', async () => {
mockRequest.mockResolvedValue({
tag: 'right',
value: {
status: Api.HttpStatusCode.Ok,
data: {}
}
});
const api = portfolioApiMaker({
network: mockNetwork,
request: mockRequest,
maxIdsPerRequest: 10,
maxConcurrentRequests: 10
});
const mockTokenIdsWithCache = [['token.id', 'etag-hash']];
const mockTokenIdsWithCacheRequest = ['token.id:etag-hash'];
await api.tokenDiscovery(tokenDiscoveryMocks.nftCryptoKitty.id);
await api.tokenInfos(mockTokenIdsWithCache);
await api.tokenTraits(tokenMocks.nftCryptoKitty.info.id);
await api.tokenInfo(tokenMocks.nftCryptoKitty.info.id);
await api.tokenActivity(tokenActivityMocks.api.request, Portfolio.Token.ActivityWindow.OneDay);
await api.tokenHistory(tokenHistoryMocks.api.request.tokenId, tokenHistoryMocks.api.request.period);
expect(mockRequest).toHaveBeenCalledTimes(6);
expect(mockRequest).toHaveBeenCalledWith({
method: 'get',
url: apiConfig[Chain.Network.Mainnet].tokenDiscovery + '/' + tokenDiscoveryMocks.nftCryptoKitty.id,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
expect(mockRequest).toHaveBeenCalledWith({
method: 'post',
url: apiConfig[Chain.Network.Mainnet].tokenInfos,
data: mockTokenIdsWithCacheRequest,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
expect(mockRequest).toHaveBeenCalledWith({
method: 'get',
url: apiConfig[Chain.Network.Mainnet].tokenTraits + '/' + tokenMocks.nftCryptoKitty.info.id,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
expect(mockRequest).toHaveBeenCalledWith({
method: 'get',
url: apiConfig[Chain.Network.Mainnet].tokenInfo + '/' + tokenMocks.nftCryptoKitty.info.id,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
expect(mockRequest).toHaveBeenCalledWith({
method: 'post',
url: `${apiConfig[Chain.Network.Mainnet].tokenActivity}/${Portfolio.Token.ActivityWindow.OneDay}`,
data: tokenActivityMocks.api.request,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
expect(mockRequest).toHaveBeenCalledWith({
method: 'post',
url: apiConfig[Chain.Network.Mainnet].tokenHistory,
data: tokenHistoryMocks.api.request,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
});
it('should return error when returning data is malformed', async () => {
mockRequest.mockResolvedValue({
tag: 'right',
value: {
status: Api.HttpStatusCode.Ok,
data: {
['wrong']: [200, 'data']
}
}
});
const api = portfolioApiMaker({
network: mockNetwork,
request: mockRequest,
maxIdsPerRequest: 10,
maxConcurrentRequests: 10
});
const resultDiscovery = await api.tokenDiscovery(tokenDiscoveryMocks.nftCryptoKitty.id);
expect(mockRequest).toHaveBeenCalledTimes(1);
expect(mockRequest).toHaveBeenCalledWith({
method: 'get',
url: apiConfig[Chain.Network.Mainnet].tokenDiscovery + '/' + tokenDiscoveryMocks.nftCryptoKitty.id,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
expect(resultDiscovery).toEqual({
tag: 'left',
error: {
status: -3,
message: 'Failed to transform token discovery response',
responseData: {
['wrong']: [200, 'data']
}
}
});
const resultInfo = await api.tokenInfo(tokenMocks.nftCryptoKitty.info.id);
expect(mockRequest).toHaveBeenCalledTimes(2);
expect(mockRequest).toHaveBeenCalledWith({
method: 'get',
url: apiConfig[Chain.Network.Mainnet].tokenInfo + '/' + tokenMocks.nftCryptoKitty.info.id,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
expect(resultInfo).toEqual({
tag: 'left',
error: {
status: -3,
message: 'Failed to transform token info response',
responseData: {
['wrong']: [200, 'data']
}
}
});
const resultTokenActivity = await api.tokenActivity(tokenActivityMocks.api.request, Portfolio.Token.ActivityWindow.OneDay);
expect(mockRequest).toHaveBeenCalledTimes(3);
expect(mockRequest).toHaveBeenCalledWith({
method: 'post',
url: `${apiConfig[Chain.Network.Mainnet].tokenActivity}/${Portfolio.Token.ActivityWindow.OneDay}`,
data: tokenActivityMocks.api.request,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
expect(resultTokenActivity).toEqual({
tag: 'right',
value: {
status: 200,
data: {}
}
});
const resultTokenHistory = await api.tokenHistory(tokenHistoryMocks.api.request.tokenId, tokenHistoryMocks.api.request.period);
expect(mockRequest).toHaveBeenCalledTimes(4);
expect(mockRequest).toHaveBeenCalledWith({
method: 'post',
url: apiConfig[Chain.Network.Mainnet].tokenHistory,
data: tokenHistoryMocks.api.request,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
expect(resultTokenHistory).toEqual({
tag: 'left',
error: {
status: -3,
message: 'Failed to transform token history response',
responseData: {
['wrong']: [200, 'data']
}
}
});
});
it('should return the error and not throw', async () => {
mockRequest.mockResolvedValue({
tag: 'left',
value: {
status: Api.HttpStatusCode.InternalServerError,
message: 'Internal Server Error',
responseData: {}
}
});
const api = portfolioApiMaker({
network: mockNetwork,
request: mockRequest,
maxIdsPerRequest: 10,
maxConcurrentRequests: 10
});
const mockTokenIdsWithCache = [['token.id', 'etag-hash']];
const mockTokenIdsWithCacheRequest = ['token.id:etag-hash'];
await expect(api.tokenInfos(mockTokenIdsWithCache)).resolves.toEqual({
tag: 'left',
value: {
status: Api.HttpStatusCode.InternalServerError,
message: 'Internal Server Error',
responseData: {}
}
});
expect(mockRequest).toHaveBeenCalledTimes(1);
expect(mockRequest).toHaveBeenCalledWith({
method: 'post',
url: apiConfig[Chain.Network.Mainnet].tokenInfos,
data: mockTokenIdsWithCacheRequest,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
await expect(api.tokenDiscovery(tokenDiscoveryMocks.nftCryptoKitty.id)).resolves.toEqual({
tag: 'left',
value: {
status: Api.HttpStatusCode.InternalServerError,
message: 'Internal Server Error',
responseData: {}
}
});
expect(mockRequest).toHaveBeenCalledTimes(2);
expect(mockRequest).toHaveBeenCalledWith({
method: 'get',
url: apiConfig[Chain.Network.Mainnet].tokenDiscovery + '/' + tokenDiscoveryMocks.nftCryptoKitty.id,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
await expect(api.tokenTraits(tokenMocks.nftCryptoKitty.info.id)).resolves.toEqual({
tag: 'left',
value: {
status: Api.HttpStatusCode.InternalServerError,
message: 'Internal Server Error',
responseData: {}
}
});
expect(mockRequest).toHaveBeenCalledTimes(3);
expect(mockRequest).toHaveBeenCalledWith({
method: 'get',
url: apiConfig[Chain.Network.Mainnet].tokenTraits + '/' + tokenMocks.nftCryptoKitty.info.id,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
await expect(api.tokenInfo(tokenMocks.nftCryptoKitty.info.id)).resolves.toEqual({
tag: 'left',
value: {
status: Api.HttpStatusCode.InternalServerError,
message: 'Internal Server Error',
responseData: {}
}
});
expect(mockRequest).toHaveBeenCalledTimes(4);
expect(mockRequest).toHaveBeenCalledWith({
method: 'get',
url: apiConfig[Chain.Network.Mainnet].tokenInfo + '/' + tokenMocks.nftCryptoKitty.info.id,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
await expect(api.tokenActivity(tokenActivityMocks.api.request, Portfolio.Token.ActivityWindow.OneDay)).resolves.toEqual({
tag: 'left',
value: {
status: Api.HttpStatusCode.InternalServerError,
message: 'Internal Server Error',
responseData: {}
}
});
expect(mockRequest).toHaveBeenCalledTimes(5);
expect(mockRequest).toHaveBeenCalledWith({
method: 'post',
url: `${apiConfig[Chain.Network.Mainnet].tokenActivity}/${Portfolio.Token.ActivityWindow.OneDay}`,
data: tokenActivityMocks.api.request,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
await expect(api.tokenHistory(tokenHistoryMocks.api.request.tokenId, tokenHistoryMocks.api.request.period)).resolves.toEqual({
tag: 'left',
value: {
status: Api.HttpStatusCode.InternalServerError,
message: 'Internal Server Error',
responseData: {}
}
});
expect(mockRequest).toHaveBeenCalledTimes(6);
expect(mockRequest).toHaveBeenCalledWith({
method: 'post',
url: apiConfig[Chain.Network.Mainnet].tokenHistory,
data: tokenHistoryMocks.api.request,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
});
it('should return the data on success (traits)', async () => {
mockRequest.mockResolvedValue({
tag: 'right',
value: {
status: Api.HttpStatusCode.Ok,
data: tokenMocks.nftCryptoKitty.traits
}
});
const api = portfolioApiMaker({
network: mockNetwork,
request: mockRequest,
maxIdsPerRequest: 10,
maxConcurrentRequests: 10
});
const result = await api.tokenTraits(tokenMocks.nftCryptoKitty.info.id);
expect(mockRequest).toHaveBeenCalledTimes(1);
expect(mockRequest).toHaveBeenCalledWith({
method: 'get',
url: apiConfig[Chain.Network.Mainnet].tokenTraits + '/' + tokenMocks.nftCryptoKitty.info.id,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
expect(result).toEqual({
tag: 'right',
value: {
status: Api.HttpStatusCode.Ok,
data: tokenMocks.nftCryptoKitty.traits
}
});
});
it('should return the data on success (tokenInfo)', async () => {
mockRequest.mockResolvedValue({
tag: 'right',
value: {
status: Api.HttpStatusCode.Ok,
data: tokenMocks.nftCryptoKitty.info
}
});
const api = portfolioApiMaker({
network: mockNetwork,
request: mockRequest,
maxIdsPerRequest: 10,
maxConcurrentRequests: 10
});
const result = await api.tokenInfo(tokenMocks.nftCryptoKitty.info.id);
expect(mockRequest).toHaveBeenCalledTimes(1);
expect(mockRequest).toHaveBeenCalledWith({
method: 'get',
url: apiConfig[Chain.Network.Mainnet].tokenInfo + '/' + tokenMocks.nftCryptoKitty.info.id,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
expect(result).toEqual({
tag: 'right',
value: {
status: Api.HttpStatusCode.Ok,
data: tokenMocks.nftCryptoKitty.info
}
});
});
it('should return the data on success (tokenActivity)', async () => {
mockRequest.mockResolvedValue(tokenActivityMocks.api.responses.success);
const api = portfolioApiMaker({
network: mockNetwork,
request: mockRequest,
maxIdsPerRequest: 10,
maxConcurrentRequests: 10
});
const result = await api.tokenActivity(tokenActivityMocks.api.request, Portfolio.Token.ActivityWindow.OneDay);
expect(mockRequest).toHaveBeenCalledTimes(1);
expect(mockRequest).toHaveBeenCalledWith({
method: 'post',
url: `${apiConfig[Chain.Network.Mainnet].tokenActivity}/${Portfolio.Token.ActivityWindow.OneDay}`,
data: tokenActivityMocks.api.request,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
expect(result).toEqual({
tag: 'right',
value: {
status: Api.HttpStatusCode.Ok,
data: tokenActivityMocks.api.responseDataOnly
}
});
});
it('should return the data on success (tokenHistory)', async () => {
mockRequest.mockResolvedValue(tokenHistoryMocks.api.responses.success);
const api = portfolioApiMaker({
network: mockNetwork,
request: mockRequest,
maxIdsPerRequest: 10,
maxConcurrentRequests: 10
});
const result = await api.tokenHistory(tokenHistoryMocks.api.request.tokenId, tokenHistoryMocks.api.request.period);
expect(mockRequest).toHaveBeenCalledTimes(1);
expect(mockRequest).toHaveBeenCalledWith({
method: 'post',
url: apiConfig[Chain.Network.Mainnet].tokenHistory,
data: tokenHistoryMocks.api.request,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
expect(result).toEqual({
tag: 'right',
value: {
status: Api.HttpStatusCode.Ok,
data: tokenHistoryMocks.api.responseDataOnly
}
});
});
it('should return error when returning data is malformed token-discovery', async () => {
mockRequest.mockResolvedValue({
tag: 'right',
value: {
status: Api.HttpStatusCode.Ok,
data: 0
}
});
const api = portfolioApiMaker({
network: mockNetwork,
request: mockRequest,
maxIdsPerRequest: 10,
maxConcurrentRequests: 10
});
const wrong = await api.tokenDiscovery(tokenDiscoveryMocks.nftCryptoKitty.id);
expect(mockRequest).toHaveBeenCalledTimes(1);
expect(mockRequest).toHaveBeenCalledWith({
method: 'get',
url: apiConfig[Chain.Network.Mainnet].tokenDiscovery + '/' + tokenDiscoveryMocks.nftCryptoKitty.id,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
expect(wrong).toEqual({
tag: 'left',
error: {
status: -3,
message: 'Failed to transform token discovery response',
responseData: 0
}
});
mockRequest.mockResolvedValue({
tag: 'right',
value: {
status: Api.HttpStatusCode.Ok,
data: {
...tokenDiscoveryMocks.nftCryptoKitty,
supply: undefined
}
}
});
const missing = await api.tokenDiscovery(tokenDiscoveryMocks.nftCryptoKitty.id);
expect(missing).toEqual({
tag: 'left',
error: {
status: -3,
message: 'Failed to transform token discovery response',
responseData: {
...tokenDiscoveryMocks.nftCryptoKitty,
supply: undefined
}
}
});
expect(mockRequest).toHaveBeenCalledTimes(2);
mockRequest.mockResolvedValue({
tag: 'right',
value: {
status: Api.HttpStatusCode.Ok,
data: tokenDiscoveryMocks.nftCryptoKitty
}
});
const right = await api.tokenDiscovery(tokenDiscoveryMocks.nftCryptoKitty.id);
expect(right).toEqual({
tag: 'right',
value: {
status: Api.HttpStatusCode.Ok,
data: tokenDiscoveryMocks.nftCryptoKitty
}
});
});
it('should return nothing when invalidating image', async () => {
mockRequest.mockResolvedValue({
tag: 'right',
value: {
status: Api.HttpStatusCode.Ok,
data: {}
}
});
const api = portfolioApiMaker({
network: mockNetwork,
request: mockRequest,
maxIdsPerRequest: 10,
maxConcurrentRequests: 10
});
await api.tokenImageInvalidate(tokenImageInvalidateMocks.api.request);
expect(mockRequest).toHaveBeenCalledTimes(1);
});
});
//# sourceMappingURL=api-maker.test.js.map