@yoroi/portfolio
Version:
The Portfolio package of Yoroi SDK
214 lines (207 loc) • 8.53 kB
JavaScript
"use strict";
var _common = require("@yoroi/common");
var _types = require("@yoroi/types");
var _tokenManager = require("./token-manager");
var _tokenStorageMaker = require("./adapters/mmkv-storage/token-storage-maker");
var _apiMaker = require("./adapters/dullahan-api/api-maker.mocks");
var _tokenInfo = require("./adapters/token-info.mocks");
var _createCachedUnknownTokenInfo = require("./helpers/create-cached-unknown-token-info");
describe('portfolioTokenManagerMaker', () => {
const tokenInfoStorage = (0, _common.observableStorageMaker)((0, _common.mountMMKVStorage)({
path: `/test/token-info/`
}));
const storage = (0, _tokenStorageMaker.portfolioTokenStorageMaker)({
tokenInfoStorage
});
afterEach(() => {
jest.resetAllMocks();
storage.clear();
});
it('should hydrate the cache', () => {
const api = _apiMaker.portfolioApiMock.success;
const manager = (0, _tokenManager.portfolioTokenManagerMaker)({
api,
storage
});
const subscriber = jest.fn();
manager.subscribe(subscriber);
manager.hydrate({
sourceId: 'sourceId'
});
expect(subscriber).toHaveBeenCalledTimes(1);
expect(subscriber).toHaveBeenCalledWith({
on: _types.Portfolio.Event.ManagerOn.Hydrate,
sourceId: 'sourceId'
});
});
it('should sync token infos with unknowns', async () => {
storage.token.infos.save(_tokenInfo.tokenInfoMocks.storage.notModified);
const api = _apiMaker.portfolioApiMock.success;
const manager = (0, _tokenManager.portfolioTokenManagerMaker)({
api,
storage
});
const unknownTokenId = 'unknown.id';
const secondaryTokenIds = [_tokenInfo.tokenInfoMocks.rnftWhatever.id, _tokenInfo.tokenInfoMocks.nftCryptoKitty.id, unknownTokenId];
manager.hydrate({
sourceId: 'sourceId'
});
const subscriber = jest.fn();
manager.subscribe(subscriber);
const unknownCachedTokenInfo = (0, _createCachedUnknownTokenInfo.createCachedUnknownTokenInfo)(unknownTokenId);
const result = await manager.sync({
secondaryTokenIds,
sourceId: 'sourceId'
});
expect(subscriber).toHaveBeenCalledTimes(1);
expect(subscriber).toHaveBeenCalledWith({
on: _types.Portfolio.Event.ManagerOn.Sync,
ids: expect.arrayContaining(secondaryTokenIds.slice(1)),
sourceId: 'sourceId'
});
expect(result.size).toBe(3);
// should update the stale cache records with api data and refresh cache info
const resultNftCryptoKitty = result.get(_tokenInfo.tokenInfoMocks.nftCryptoKitty.id);
if (!resultNftCryptoKitty) fail();
expect(resultNftCryptoKitty.expires).toBeGreaterThan(Date.now());
expect(resultNftCryptoKitty.hash).toBe('hash2-1');
expect(resultNftCryptoKitty.record).toEqual(_tokenInfo.tokenInfoMocks.nftCryptoKitty);
// should create unknown token info when api doesn't return it
// creates expired so it will always hit the api when syncing
const resultUnknownToken = result.get(unknownTokenId);
if (!resultUnknownToken) fail();
expect(resultUnknownToken.expires).toBe(0);
expect(resultUnknownToken.hash).toBe('');
expect(resultUnknownToken.record).toEqual(unknownCachedTokenInfo.record);
// should return the cached record when api returns NotModified
// yet, should update the expires but not the hash
const resultRnftWhatever = result.get(_tokenInfo.tokenInfoMocks.rnftWhatever.id);
if (!resultRnftWhatever) fail();
expect(resultRnftWhatever.expires).toBeGreaterThan(Date.now());
expect(resultRnftWhatever.hash).toBe('hash3');
expect(resultRnftWhatever.record).toEqual(_tokenInfo.tokenInfoMocks.rnftWhatever);
manager.destroy();
});
it('should read all from cache', async () => {
storage.token.infos.save(_tokenInfo.tokenInfoMocks.storage.cached);
const api = _apiMaker.portfolioApiMock.success;
const manager = (0, _tokenManager.portfolioTokenManagerMaker)({
api,
storage
});
const secondaryTokenIds = [_tokenInfo.tokenInfoMocks.rnftWhatever.id];
const result = await manager.sync({
secondaryTokenIds,
sourceId: 'sourceId'
});
expect(result.size).toBe(1);
// should return the cached record and not hit the api
const resultRnftWhatever = result.get(_tokenInfo.tokenInfoMocks.rnftWhatever.id);
if (!resultRnftWhatever) fail();
expect(resultRnftWhatever.expires).toBeGreaterThan(Date.now());
expect(resultRnftWhatever.hash).toBe('hash3');
expect(resultRnftWhatever.record).toEqual(_tokenInfo.tokenInfoMocks.rnftWhatever);
});
it('should create as unknwon when api error', async () => {
const api = _apiMaker.portfolioApiMock.error;
const manager = (0, _tokenManager.portfolioTokenManagerMaker)({
api,
storage
});
const secondaryTokenIds = [_tokenInfo.tokenInfoMocks.rnftWhatever.id];
const unknownCachedTokenInfo = (0, _createCachedUnknownTokenInfo.createCachedUnknownTokenInfo)(_tokenInfo.tokenInfoMocks.rnftWhatever.id);
const result = await manager.sync({
secondaryTokenIds,
sourceId: 'sourceId'
});
expect(result.size).toBe(1);
// should return the unknown record
const resultRnftWhatever = result.get(_tokenInfo.tokenInfoMocks.rnftWhatever.id);
if (!resultRnftWhatever) fail();
expect(resultRnftWhatever).toEqual(unknownCachedTokenInfo);
});
it('should call destroy (coverage) observer is not exposed', () => {
const api = _apiMaker.portfolioApiMock.success;
const manager = (0, _tokenManager.portfolioTokenManagerMaker)({
api,
storage
});
manager.destroy();
});
it('should revalidate cache', async () => {
const api = _apiMaker.portfolioApiMock.success;
storage.token.infos.save(_tokenInfo.tokenInfoMocks.storage.notModified);
const manager = (0, _tokenManager.portfolioTokenManagerMaker)({
api,
storage
});
const secondaryTokenIds = [_tokenInfo.tokenInfoMocks.rnftWhatever.id];
const result = await manager.sync({
secondaryTokenIds,
sourceId: 'sourceId'
});
expect(result.size).toBe(1);
// should return the unknown record
const resultRnftWhatever = result.get(_tokenInfo.tokenInfoMocks.rnftWhatever.id);
if (!resultRnftWhatever) fail();
expect(resultRnftWhatever.expires).toBeGreaterThan(Date.now());
expect(resultRnftWhatever.hash).toBe('hash3');
expect(resultRnftWhatever.record).toEqual(_tokenInfo.tokenInfoMocks.rnftWhatever);
});
it('should sync empty', async () => {
const api = _apiMaker.portfolioApiMock.success;
storage.token.infos.save(_tokenInfo.tokenInfoMocks.storage.notModified);
const manager = (0, _tokenManager.portfolioTokenManagerMaker)({
api,
storage
});
const secondaryTokenIds = [];
const result = await manager.sync({
secondaryTokenIds,
sourceId: 'sourceId'
});
expect(result.size).toBe(0);
});
it('should sync empty to revalidate', async () => {
const api = _apiMaker.portfolioApiMock.success;
const manager = (0, _tokenManager.portfolioTokenManagerMaker)({
api,
storage
});
const secondaryTokenIds = [_tokenInfo.tokenInfoMocks.rnftWhatever.id];
const unknownCachedTokenInfo = (0, _createCachedUnknownTokenInfo.createCachedUnknownTokenInfo)(_tokenInfo.tokenInfoMocks.rnftWhatever.id);
const result = await manager.sync({
secondaryTokenIds,
sourceId: 'sourceId'
});
expect(result.size).toBe(1);
const resultRnftWhatever = result.get(_tokenInfo.tokenInfoMocks.rnftWhatever.id);
if (!resultRnftWhatever) fail();
expect(resultRnftWhatever).toEqual(unknownCachedTokenInfo);
});
it('should clear all data in the storage', async () => {
const api = _apiMaker.portfolioApiMock.success;
const manager = (0, _tokenManager.portfolioTokenManagerMaker)({
api,
storage
});
const secondaryTokenIds = [_tokenInfo.tokenInfoMocks.rnftWhatever.id];
await manager.sync({
secondaryTokenIds,
sourceId: 'sourceId'
});
expect(storage.token.infos.read([_tokenInfo.tokenInfoMocks.rnftWhatever.id]).length).toBe(1);
const subscriber = jest.fn();
manager.subscribe(subscriber);
manager.clear({
sourceId: 'sourceId'
});
expect(storage.token.infos.all().length).toBe(0);
expect(subscriber).toHaveBeenCalledWith({
on: _types.Portfolio.Event.ManagerOn.Clear,
sourceId: 'sourceId'
});
manager.destroy();
});
});
//# sourceMappingURL=token-manager.test.js.map