Changeset View
Changeset View
Standalone View
Standalone View
cashtab/src/hooks/__tests__/useWallet.test.js
// Copyright (c) 2024 The Bitcoin developers | // Copyright (c) 2024 The Bitcoin developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
import useWallet from '../useWallet'; | import useWallet from '../useWallet'; | ||||
import { renderHook, waitFor, act } from '@testing-library/react'; | import { renderHook, waitFor, act } from '@testing-library/react'; | ||||
import 'fake-indexeddb/auto'; | import 'fake-indexeddb/auto'; | ||||
import localforage from 'localforage'; | import localforage from 'localforage'; | ||||
import { | import { | ||||
walletWithXecAndTokens, | |||||
cashtabSettingsGbp, | cashtabSettingsGbp, | ||||
nonDefaultContactList, | nonDefaultContactList, | ||||
nonDefaultCashtabCache, | nonDefaultCashtabCache, | ||||
mockIncomingTokenTxDetails, | mockIncomingTokenTxDetails, | ||||
} from 'hooks/fixtures/mocks'; | } from 'hooks/fixtures/mocks'; | ||||
import appConfig from 'config/app'; | import appConfig from 'config/app'; | ||||
import { when } from 'jest-when'; | import { when } from 'jest-when'; | ||||
import { | import { | ||||
clearLocalForage, | clearLocalForage, | ||||
initializeCashtabStateForTests, | initializeCashtabStateForTests, | ||||
} from 'components/fixtures/helpers'; | } from 'components/fixtures/helpers'; | ||||
import aliasSettings from 'config/alias'; | import aliasSettings from 'config/alias'; | ||||
import { cashtabCacheToJSON, storedCashtabCacheToMap } from 'helpers'; | import { cashtabCacheToJSON, storedCashtabCacheToMap } from 'helpers'; | ||||
import CashtabCache from 'config/CashtabCache'; | import CashtabCache from 'config/CashtabCache'; | ||||
import { | |||||
walletWithXecAndTokens, | |||||
mockCacheWalletWithXecAndTokens, | |||||
mockCachedInfoCashtabDark, | |||||
} from 'components/fixtures/mocks'; | |||||
describe('useWallet hook rendering in different localforage states', () => { | describe('useWallet hook rendering in different localforage states', () => { | ||||
const xecPrice = 0.00003; | const xecPrice = 0.00003; | ||||
const priceResponse = { | const priceResponse = { | ||||
ecash: { | ecash: { | ||||
usd: xecPrice, | usd: xecPrice, | ||||
last_updated_at: 1706644626, | last_updated_at: 1706644626, | ||||
}, | }, | ||||
Show All 16 Lines | afterEach(async () => { | ||||
jest.clearAllMocks(); | jest.clearAllMocks(); | ||||
await clearLocalForage(localforage); | await clearLocalForage(localforage); | ||||
}); | }); | ||||
it('localforage can set and get a map of tokeninfo by tokenId', async () => { | it('localforage can set and get a map of tokeninfo by tokenId', async () => { | ||||
const mockTokenCache = new Map(); | const mockTokenCache = new Map(); | ||||
mockTokenCache.set( | mockTokenCache.set( | ||||
'3fee3384150b030490b7bee095a63900f66a45f2d8e3002ae2cf17ce3ef4d109', | '3fee3384150b030490b7bee095a63900f66a45f2d8e3002ae2cf17ce3ef4d109', | ||||
{ | mockCacheWalletWithXecAndTokens, | ||||
tokenTicker: 'BEAR', | |||||
tokenName: 'BearNip', | |||||
url: 'https://cashtab.com/', | |||||
decimals: 0, | |||||
hash: '', | |||||
}, | |||||
); | ); | ||||
mockTokenCache.set( | mockTokenCache.set( | ||||
'b8f2a9e767a0be7b80c7e414ef2534586d4da72efddb39a4e70e501ab73375cc', | 'b8f2a9e767a0be7b80c7e414ef2534586d4da72efddb39a4e70e501ab73375cc', | ||||
{ | mockCachedInfoCashtabDark, | ||||
tokenTicker: 'CTD', | |||||
tokenName: 'Cashtab Dark', | |||||
url: 'https://cashtab.com/', | |||||
decimals: 0, | |||||
hash: '', | |||||
}, | |||||
); | ); | ||||
const mockCashtabCache = { tokens: mockTokenCache }; | const mockCashtabCache = { tokens: mockTokenCache }; | ||||
await localforage.setItem( | await localforage.setItem( | ||||
'testCache', | 'testCache', | ||||
cashtabCacheToJSON(mockCashtabCache), | cashtabCacheToJSON(mockCashtabCache), | ||||
); | ); | ||||
▲ Show 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | it('Cashtab loads wallet, settings, cache, and contactlist from localforage to context if they are present', async () => { | ||||
const expectedUpdatedCache = storedCashtabCacheToMap( | const expectedUpdatedCache = storedCashtabCacheToMap( | ||||
JSON.parse( | JSON.parse( | ||||
JSON.stringify(cashtabCacheToJSON(nonDefaultCashtabCache)), | JSON.stringify(cashtabCacheToJSON(nonDefaultCashtabCache)), | ||||
), | ), | ||||
); | ); | ||||
expectedUpdatedCache.tokens.set( | expectedUpdatedCache.tokens.set( | ||||
'3fee3384150b030490b7bee095a63900f66a45f2d8e3002ae2cf17ce3ef4d109', | '3fee3384150b030490b7bee095a63900f66a45f2d8e3002ae2cf17ce3ef4d109', | ||||
{ | mockCacheWalletWithXecAndTokens, | ||||
decimals: 0, | |||||
success: true, | |||||
tokenDocumentHash: '', | |||||
tokenDocumentUrl: 'https://cashtab.com/', | |||||
tokenName: 'BearNip', | |||||
tokenTicker: 'BEAR', | |||||
}, | |||||
); | ); | ||||
await waitFor(() => | await waitFor(() => | ||||
expect(result.current.cashtabState.cashtabCache).toEqual( | expect(result.current.cashtabState.cashtabCache).toEqual( | ||||
expectedUpdatedCache, | expectedUpdatedCache, | ||||
), | ), | ||||
); | ); | ||||
await waitFor(() => | await waitFor(() => | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | it('processChronikWsMsg() refreshes alias prices when aliasPrices is null', async () => { | ||||
// Wait for the wallet to load | // Wait for the wallet to load | ||||
await waitFor(() => | await waitFor(() => | ||||
expect(result.current.cashtabState.wallets[0]).toStrictEqual( | expect(result.current.cashtabState.wallets[0]).toStrictEqual( | ||||
walletWithXecAndTokens, | walletWithXecAndTokens, | ||||
), | ), | ||||
); | ); | ||||
await act(async () => { | await act(async () => { | ||||
await result.current.processChronikWsMsg(mockWebsocketMsg); | await result.current.processChronikWsMsg( | ||||
mockWebsocketMsg, | |||||
result.current.cashtabState, | |||||
result.current.fiatPrice, | |||||
); | |||||
}); | }); | ||||
// Verify upon `BlockConnected` events processChronikWsMsg() updates the aliasPrices state var | // Verify upon `BlockConnected` events processChronikWsMsg() updates the aliasPrices state var | ||||
expect(result.current.aliasPrices).toStrictEqual( | expect(result.current.aliasPrices).toStrictEqual( | ||||
mockAliasServerResponse, | mockAliasServerResponse, | ||||
); | ); | ||||
}); | }); | ||||
▲ Show 20 Lines • Show All 108 Lines • ▼ Show 20 Lines | it('processChronikWsMsg() refreshes alias prices when aliasPrices exists, server and cashtab prices array length do not match', async () => { | ||||
// Wait for the wallet to load | // Wait for the wallet to load | ||||
await waitFor(() => | await waitFor(() => | ||||
expect(result.current.cashtabState.wallets[0]).toStrictEqual( | expect(result.current.cashtabState.wallets[0]).toStrictEqual( | ||||
walletWithXecAndTokens, | walletWithXecAndTokens, | ||||
), | ), | ||||
); | ); | ||||
await act(async () => { | await act(async () => { | ||||
await result.current.processChronikWsMsg(mockWebsocketMsg); | await result.current.processChronikWsMsg( | ||||
mockWebsocketMsg, | |||||
result.current.cashtabState, | |||||
result.current.fiatPrice, | |||||
); | |||||
}); | }); | ||||
// Verify upon `BlockConnected` events processChronikWsMsg() updates the aliasPrices state var | // Verify upon `BlockConnected` events processChronikWsMsg() updates the aliasPrices state var | ||||
expect(result.current.aliasPrices).toEqual(mockAliasServerResponse); | expect(result.current.aliasPrices).toEqual(mockAliasServerResponse); | ||||
}); | }); | ||||
it('processChronikWsMsg() does not refresh alias prices when aliasPrices exists, server and cashtab array length do match', async () => { | it('processChronikWsMsg() does not refresh alias prices when aliasPrices exists, server and cashtab array length do match', async () => { | ||||
const mockedChronik = await initializeCashtabStateForTests( | const mockedChronik = await initializeCashtabStateForTests( | ||||
▲ Show 20 Lines • Show All 137 Lines • ▼ Show 20 Lines | it('processChronikWsMsg() does not refresh alias prices when aliasPrices exists, server and cashtab array length do match', async () => { | ||||
global.fetch = jest.fn(); | global.fetch = jest.fn(); | ||||
when(fetch) | when(fetch) | ||||
.calledWith(fetchUrl) | .calledWith(fetchUrl) | ||||
.mockResolvedValue({ | .mockResolvedValue({ | ||||
json: () => Promise.resolve(mockAliasServerResponse), | json: () => Promise.resolve(mockAliasServerResponse), | ||||
}); | }); | ||||
await act(async () => { | await act(async () => { | ||||
await result.current.processChronikWsMsg(mockWebsocketMsg); | await result.current.processChronikWsMsg( | ||||
mockWebsocketMsg, | |||||
result.current.cashtabState, | |||||
result.current.fiatPrice, | |||||
); | |||||
}); | }); | ||||
// Verify upon `BlockConnected` events processChronikWsMsg() does not update the aliasPrices state var | // Verify upon `BlockConnected` events processChronikWsMsg() does not update the aliasPrices state var | ||||
expect(result.current.aliasPrices).toStrictEqual( | expect(result.current.aliasPrices).toStrictEqual( | ||||
mockExistingAliasPrices, | mockExistingAliasPrices, | ||||
); | ); | ||||
}); | }); | ||||
Show All 18 Lines | it('Verify a processChronikWsMsg() new block event updates the `aliasServerError` state var upon a /prices/ endpoint error', async () => { | ||||
// Wait for the wallet to load | // Wait for the wallet to load | ||||
await waitFor(() => | await waitFor(() => | ||||
expect(result.current.cashtabState.wallets[0]).toStrictEqual( | expect(result.current.cashtabState.wallets[0]).toStrictEqual( | ||||
walletWithXecAndTokens, | walletWithXecAndTokens, | ||||
), | ), | ||||
); | ); | ||||
await act(async () => { | await act(async () => { | ||||
await result.current.processChronikWsMsg(mockWebsocketMsg); | await result.current.processChronikWsMsg( | ||||
mockWebsocketMsg, | |||||
result.current.cashtabState, | |||||
result.current.fiatPrice, | |||||
); | |||||
}); | }); | ||||
// Verify the `aliasServerError` state var in useWallet is updated | // Verify the `aliasServerError` state var in useWallet is updated | ||||
expect(result.current.aliasServerError).toStrictEqual( | expect(result.current.aliasServerError).toStrictEqual( | ||||
new Error(expectedError), | new Error(expectedError), | ||||
); | ); | ||||
}); | }); | ||||
▲ Show 20 Lines • Show All 105 Lines • ▼ Show 20 Lines | it('An incoming tx message from the websocket causes the wallet to update', async () => { | ||||
expect(result.current.cashtabState.wallets[0]).toStrictEqual( | expect(result.current.cashtabState.wallets[0]).toStrictEqual( | ||||
walletWithXecAndTokens, | walletWithXecAndTokens, | ||||
), | ), | ||||
); | ); | ||||
const expectedCache = new CashtabCache(); | const expectedCache = new CashtabCache(); | ||||
expectedCache.tokens.set( | expectedCache.tokens.set( | ||||
'3fee3384150b030490b7bee095a63900f66a45f2d8e3002ae2cf17ce3ef4d109', | '3fee3384150b030490b7bee095a63900f66a45f2d8e3002ae2cf17ce3ef4d109', | ||||
{ | mockCacheWalletWithXecAndTokens, | ||||
decimals: 0, | |||||
success: true, | |||||
tokenDocumentHash: '', | |||||
tokenDocumentUrl: 'https://cashtab.com/', | |||||
tokenName: 'BearNip', | |||||
tokenTicker: 'BEAR', | |||||
}, | |||||
); | ); | ||||
// cashtabCache has one token added from tx history | // cashtabCache has one token added from tx history | ||||
await waitFor(() => | await waitFor(() => | ||||
expect(result.current.cashtabState.cashtabCache).toEqual( | expect(result.current.cashtabState.cashtabCache).toEqual( | ||||
expectedCache, | expectedCache, | ||||
), | ), | ||||
); | ); | ||||
Show All 22 Lines |