Changeset View
Changeset View
Standalone View
Standalone View
cashtab/src/components/fixtures/__tests__/index.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 vectors from 'components/fixtures/vectors'; | import vectors from 'components/fixtures/vectors'; | ||||
import { | import { | ||||
initializeCashtabStateForTests, | initializeCashtabStateForTests, | ||||
initializeCashtabStateAtLegacyWalletKeysForTests, | initializeCashtabStateAtLegacyWalletKeysForTests, | ||||
clearLocalForage, | clearLocalForage, | ||||
} from 'components/fixtures/helpers'; | } from 'components/fixtures/helpers'; | ||||
import 'fake-indexeddb/auto'; | import 'fake-indexeddb/auto'; | ||||
import localforage from 'localforage'; | import localforage from 'localforage'; | ||||
import { chronik as chronikConfig } from 'config/chronik'; | import { chronik as chronikConfig } from 'config/chronik'; | ||||
import { CashtabSettings } from 'config/cashtabSettings'; | import { CashtabSettings } from 'config/cashtabSettings'; | ||||
import CashtabCache from 'config/CashtabCache'; | import CashtabCache from 'config/CashtabCache'; | ||||
import { cashtabCacheToJSON } from 'helpers'; | import { cashtabCacheToJSON, cashtabWalletsFromJSON } from 'helpers'; | ||||
describe('Correctly prepares Cashtab mocked chronik client and localforage environment for Cashtab pre 1.7.* for unit tests', () => { | describe('Correctly prepares Cashtab mocked chronik client and localforage environment for Cashtab pre 1.7.* for unit tests', () => { | ||||
afterEach(async () => { | afterEach(async () => { | ||||
await clearLocalForage(localforage); | await clearLocalForage(localforage); | ||||
}); | }); | ||||
it(`initializeCashtabStateAtLegacyWalletKeysForTests mocks a new Cashtab user or incognito visitor`, async () => { | it(`initializeCashtabStateAtLegacyWalletKeysForTests mocks a new Cashtab user or incognito visitor`, async () => { | ||||
const mockedChronikClient = | const mockedChronikClient = | ||||
await initializeCashtabStateAtLegacyWalletKeysForTests( | await initializeCashtabStateAtLegacyWalletKeysForTests( | ||||
Show All 21 Lines | expectedReturns.forEach(expectedReturn => { | ||||
// First, initialize with no API error | // First, initialize with no API error | ||||
const mockChronikClient = | const mockChronikClient = | ||||
await initializeCashtabStateAtLegacyWalletKeysForTests( | await initializeCashtabStateAtLegacyWalletKeysForTests( | ||||
wallet, | wallet, | ||||
localforage, | localforage, | ||||
); | ); | ||||
const CASHTAB_TESTS_TIPHEIGHT = 800000; | const CASHTAB_TESTS_TIPHEIGHT = 800000; | ||||
const CASHTAB_ADDRESS_TYPE = 'p2pkh'; | |||||
// We can get the chaintip | // We can get the chaintip | ||||
expect(await mockChronikClient.blockchainInfo()).toEqual({ | expect(await mockChronikClient.blockchainInfo()).toEqual({ | ||||
tipHeight: CASHTAB_TESTS_TIPHEIGHT, | tipHeight: CASHTAB_TESTS_TIPHEIGHT, | ||||
}); | }); | ||||
// Path1899 utxos as expected | // Path1899 utxos as expected | ||||
expect( | expect( | ||||
await mockChronikClient | await mockChronikClient | ||||
.script(CASHTAB_ADDRESS_TYPE, wallet.Path1899.hash160) | .address(wallet.Path1899.cashAddress) | ||||
.utxos(), | .utxos(), | ||||
).toEqual({ | ).toEqual({ | ||||
outputScript: `76a914${wallet.Path1899.hash160}88ac`, | outputScript: `76a914${wallet.Path1899.hash160}88ac`, | ||||
utxos: wallet.state.nonSlpUtxos.concat(wallet.state.slpUtxos), | utxos: wallet.state.nonSlpUtxos.concat(wallet.state.slpUtxos), | ||||
}); | }); | ||||
// Path145 utxos empty | // Path145 utxos empty | ||||
expect( | expect( | ||||
await mockChronikClient | await mockChronikClient | ||||
.script(CASHTAB_ADDRESS_TYPE, wallet.Path145.hash160) | .address(wallet.Path145.cashAddress) | ||||
.utxos(), | .utxos(), | ||||
).toEqual({ | ).toEqual({ | ||||
outputScript: `76a914${wallet.Path145.hash160}88ac`, | outputScript: `76a914${wallet.Path145.hash160}88ac`, | ||||
utxos: [], | utxos: [], | ||||
}); | }); | ||||
// Path245 utxos empty | // Path245 utxos empty | ||||
expect( | expect( | ||||
await mockChronikClient | await mockChronikClient | ||||
.script(CASHTAB_ADDRESS_TYPE, wallet.Path245.hash160) | .address(wallet.Path245.cashAddress) | ||||
.utxos(), | .utxos(), | ||||
).toEqual({ | ).toEqual({ | ||||
outputScript: `76a914${wallet.Path245.hash160}88ac`, | outputScript: `76a914${wallet.Path245.hash160}88ac`, | ||||
utxos: [], | utxos: [], | ||||
}); | }); | ||||
// Path1899 history | // Path1899 history | ||||
expect( | expect( | ||||
await mockChronikClient | await mockChronikClient | ||||
.script(CASHTAB_ADDRESS_TYPE, wallet.Path1899.hash160) | .address(wallet.Path1899.cashAddress) | ||||
.history(0, chronikConfig.txHistoryCount), | .history(0, chronikConfig.txHistoryCount), | ||||
).toEqual({ numPages: 1, txs: wallet.state.parsedTxHistory }); | ).toEqual({ numPages: 1, txs: wallet.state.parsedTxHistory }); | ||||
// Path145 history empty | // Path145 history empty | ||||
expect( | expect( | ||||
await mockChronikClient | await mockChronikClient | ||||
.script(CASHTAB_ADDRESS_TYPE, wallet.Path145.hash160) | .address(wallet.Path145.cashAddress) | ||||
.history(0, chronikConfig.txHistoryCount), | .history(0, chronikConfig.txHistoryCount), | ||||
).toEqual({ | ).toEqual({ | ||||
numPages: 0, | numPages: 0, | ||||
txs: [], | txs: [], | ||||
}); | }); | ||||
// Path245 history empty | // Path245 history empty | ||||
expect( | expect( | ||||
await mockChronikClient | await mockChronikClient | ||||
.script(CASHTAB_ADDRESS_TYPE, wallet.Path245.hash160) | .address(wallet.Path245.cashAddress) | ||||
.history(0, chronikConfig.txHistoryCount), | .history(0, chronikConfig.txHistoryCount), | ||||
).toEqual({ | ).toEqual({ | ||||
numPages: 0, | numPages: 0, | ||||
txs: [], | txs: [], | ||||
}); | }); | ||||
// Next, initialize with API error | // Next, initialize with API error | ||||
const apiErrorChronikClient = await initializeCashtabStateForTests( | const apiErrorChronikClient = await initializeCashtabStateForTests( | ||||
wallet, | wallet, | ||||
localforage, | localforage, | ||||
true, | true, | ||||
); | ); | ||||
// Errors are thrown for all used methods | // Errors are thrown for all used methods | ||||
await expect( | await expect( | ||||
apiErrorChronikClient.blockchainInfo(), | apiErrorChronikClient.blockchainInfo(), | ||||
).rejects.toThrow('Error fetching blockchainInfo'); | ).rejects.toThrow('Error fetching blockchainInfo'); | ||||
await expect( | await expect( | ||||
apiErrorChronikClient | apiErrorChronikClient | ||||
.script(CASHTAB_ADDRESS_TYPE, wallet.Path1899.hash160) | .address(wallet.Path1899.cashAddress) | ||||
.utxos(), | .utxos(), | ||||
).rejects.toThrow('Error fetching utxos'); | ).rejects.toThrow('Error fetching utxos'); | ||||
await expect( | await expect( | ||||
apiErrorChronikClient | apiErrorChronikClient | ||||
.script(CASHTAB_ADDRESS_TYPE, wallet.Path145.hash160) | .address(wallet.Path145.cashAddress) | ||||
.utxos(), | .utxos(), | ||||
).rejects.toThrow('Error fetching utxos'); | ).rejects.toThrow('Error fetching utxos'); | ||||
await expect( | await expect( | ||||
apiErrorChronikClient | apiErrorChronikClient | ||||
.script(CASHTAB_ADDRESS_TYPE, wallet.Path245.hash160) | .address(wallet.Path245.cashAddress) | ||||
.utxos(), | .utxos(), | ||||
).rejects.toThrow('Error fetching utxos'); | ).rejects.toThrow('Error fetching utxos'); | ||||
await expect( | await expect( | ||||
apiErrorChronikClient | apiErrorChronikClient | ||||
.script(CASHTAB_ADDRESS_TYPE, wallet.Path1899.hash160) | .address(wallet.Path1899.cashAddress) | ||||
.history(0, chronikConfig.txHistoryCount), | .history(0, chronikConfig.txHistoryCount), | ||||
).rejects.toThrow('Error fetching history'); | ).rejects.toThrow('Error fetching history'); | ||||
await expect( | await expect( | ||||
apiErrorChronikClient | apiErrorChronikClient | ||||
.script(CASHTAB_ADDRESS_TYPE, wallet.Path145.hash160) | .address(wallet.Path145.cashAddress) | ||||
.history(0, chronikConfig.txHistoryCount), | .history(0, chronikConfig.txHistoryCount), | ||||
).rejects.toThrow('Error fetching history'); | ).rejects.toThrow('Error fetching history'); | ||||
await expect( | await expect( | ||||
apiErrorChronikClient | apiErrorChronikClient | ||||
.script(CASHTAB_ADDRESS_TYPE, wallet.Path245.hash160) | .address(wallet.Path245.cashAddress) | ||||
.history(0, chronikConfig.txHistoryCount), | .history(0, chronikConfig.txHistoryCount), | ||||
).rejects.toThrow('Error fetching history'); | ).rejects.toThrow('Error fetching history'); | ||||
// Expect localforage wallet and defaults | // Expect localforage wallet and defaults | ||||
expect(await localforage.getItem('wallet')).toEqual(wallet); | expect(await localforage.getItem('wallet')).toEqual(wallet); | ||||
// We expect the JSON conversion to be in storage | // We expect the JSON conversion to be in storage | ||||
expect(await localforage.getItem('cashtabCache')).toEqual( | expect(await localforage.getItem('cashtabCache')).toEqual( | ||||
cashtabCacheToJSON(new CashtabCache()), | cashtabCacheToJSON(new CashtabCache()), | ||||
Show All 35 Lines | expectedReturns.forEach(expectedReturn => { | ||||
it(`initializeCashtabStateForTests: ${description}`, async () => { | it(`initializeCashtabStateForTests: ${description}`, async () => { | ||||
// First, initialize with no API error | // First, initialize with no API error | ||||
const mockChronikClient = await initializeCashtabStateForTests( | const mockChronikClient = await initializeCashtabStateForTests( | ||||
wallets, | wallets, | ||||
localforage, | localforage, | ||||
); | ); | ||||
const CASHTAB_TESTS_TIPHEIGHT = 800000; | const CASHTAB_TESTS_TIPHEIGHT = 800000; | ||||
const CASHTAB_ADDRESS_TYPE = 'p2pkh'; | |||||
// We can get the chaintip | // We can get the chaintip | ||||
expect(await mockChronikClient.blockchainInfo()).toEqual({ | expect(await mockChronikClient.blockchainInfo()).toEqual({ | ||||
tipHeight: CASHTAB_TESTS_TIPHEIGHT, | tipHeight: CASHTAB_TESTS_TIPHEIGHT, | ||||
}); | }); | ||||
// All wallets have mocks ready | // All wallets have mocks ready | ||||
for (const wallet of wallets) { | for (const wallet of wallets) { | ||||
for (const path of wallet.paths) { | wallet.paths.forEach(async (pathInfo, path) => { | ||||
if (path.path === 1899) { | if (path === 1899) { | ||||
// OK to ignore because we test if/else | // OK to ignore because we test if/else | ||||
// eslint-disable-next-line jest/no-conditional-expect | // eslint-disable-next-line jest/no-conditional-expect | ||||
expect( | expect( | ||||
await mockChronikClient | await mockChronikClient | ||||
.script(CASHTAB_ADDRESS_TYPE, path.hash) | .address(pathInfo.address) | ||||
.utxos(), | .utxos(), | ||||
).toEqual({ | ).toEqual({ | ||||
outputScript: `76a914${path.hash}88ac`, | outputScript: `76a914${pathInfo.hash}88ac`, | ||||
utxos: wallet.state.nonSlpUtxos.concat( | utxos: wallet.state.nonSlpUtxos.concat( | ||||
wallet.state.slpUtxos, | wallet.state.slpUtxos, | ||||
), | ), | ||||
}); | }); | ||||
// Path1899 history | // Path1899 history | ||||
// eslint-disable-next-line jest/no-conditional-expect | // eslint-disable-next-line jest/no-conditional-expect | ||||
expect( | expect( | ||||
( | ( | ||||
await mockChronikClient | await mockChronikClient | ||||
.script(CASHTAB_ADDRESS_TYPE, path.hash) | .address(pathInfo.address) | ||||
.history(0, chronikConfig.txHistoryCount) | .history(0, chronikConfig.txHistoryCount) | ||||
).txs, | ).txs, | ||||
).toEqual(wallet.state.parsedTxHistory); | ).toEqual(wallet.state.parsedTxHistory); | ||||
} else { | } else { | ||||
// Other paths are empty | // Other paths are empty | ||||
// OK to ignore because we test if/else | // OK to ignore because we test if/else | ||||
// eslint-disable-next-line jest/no-conditional-expect | // eslint-disable-next-line jest/no-conditional-expect | ||||
expect( | expect( | ||||
await mockChronikClient | await mockChronikClient | ||||
.script(CASHTAB_ADDRESS_TYPE, path.hash) | .address(pathInfo.address) | ||||
.utxos(), | .utxos(), | ||||
).toEqual({ | ).toEqual({ | ||||
outputScript: `76a914${path.hash}88ac`, | outputScript: `76a914${pathInfo.hash}88ac`, | ||||
utxos: [], | utxos: [], | ||||
}); | }); | ||||
// history | // history | ||||
// eslint-disable-next-line jest/no-conditional-expect | // eslint-disable-next-line jest/no-conditional-expect | ||||
expect( | expect( | ||||
( | ( | ||||
await mockChronikClient | await mockChronikClient | ||||
.script(CASHTAB_ADDRESS_TYPE, path.hash) | .address(pathInfo.address) | ||||
.history(0, chronikConfig.txHistoryCount) | .history(0, chronikConfig.txHistoryCount) | ||||
).txs, | ).txs, | ||||
).toEqual([]); | ).toEqual([]); | ||||
} | } | ||||
} | }); | ||||
// Next, initialize with API error | // Next, initialize with API error | ||||
const apiErrorChronikClient = | const apiErrorChronikClient = | ||||
await initializeCashtabStateForTests( | await initializeCashtabStateForTests( | ||||
wallets, | wallets, | ||||
localforage, | localforage, | ||||
true, | true, | ||||
); | ); | ||||
// Errors are thrown for all used methods | // Errors are thrown for all used methods | ||||
await expect( | await expect( | ||||
apiErrorChronikClient.blockchainInfo(), | apiErrorChronikClient.blockchainInfo(), | ||||
).rejects.toThrow('Error fetching blockchainInfo'); | ).rejects.toThrow('Error fetching blockchainInfo'); | ||||
for (const path of wallet.paths) { | wallet.paths.forEach(async pathInfo => { | ||||
await expect( | await expect( | ||||
apiErrorChronikClient | apiErrorChronikClient.address(pathInfo.address).utxos(), | ||||
.script(CASHTAB_ADDRESS_TYPE, path.hash) | |||||
.utxos(), | |||||
).rejects.toThrow('Error fetching utxos'); | ).rejects.toThrow('Error fetching utxos'); | ||||
await expect( | await expect( | ||||
apiErrorChronikClient | apiErrorChronikClient | ||||
.script(CASHTAB_ADDRESS_TYPE, path.hash) | .address(pathInfo.address) | ||||
.history(0, chronikConfig.txHistoryCount), | .history(0, chronikConfig.txHistoryCount), | ||||
).rejects.toThrow('Error fetching history'); | ).rejects.toThrow('Error fetching history'); | ||||
} | }); | ||||
} | } | ||||
// Expect localforage wallet and defaults | // Expect localforage wallet and defaults | ||||
expect(await localforage.getItem('wallets')).toEqual(wallets); | const storedWallets = cashtabWalletsFromJSON( | ||||
await localforage.getItem('wallets'), | |||||
); | |||||
expect(storedWallets).toEqual(wallets); | |||||
// Note: we do not necessarily expect cashtabCache to be set, depends on wallet content | // Note: we do not necessarily expect cashtabCache to be set, depends on wallet content | ||||
// Note: settings would only be set if changed from defaults | // Note: settings would only be set if changed from defaults | ||||
// Note: contactList would only be set if changed from defaults | // Note: contactList would only be set if changed from defaults | ||||
}); | }); | ||||
}); | }); | ||||
}); | }); |