FIX: Currency test

This commit is contained in:
Marcos Rodriguez Velez 2024-11-19 23:16:22 -04:00
parent 1cd934aa46
commit a633f671e2
11 changed files with 218 additions and 280 deletions

View file

@ -1,17 +0,0 @@
/* global jest */
export const startIfNotStarted = jest.fn(async (key, value, callback) => {
return 666;
});
export const get = jest.fn();
export const post = jest.fn();
export const deleteMock = jest.fn();
export const stopIfRunning = jest.fn();
export const getDaemonStatus = jest.fn();
const mock = jest.fn().mockImplementation(() => {
return { startIfNotStarted, get, post, delete: deleteMock, stopIfRunning, getDaemonStatus };
});
export default mock;

View file

@ -13,6 +13,13 @@
"symbol": "د.إ.",
"country": "United Arab Emirates (UAE Dirham)"
},
"AMD": {
"endPointKey": "AMD",
"locale": "hy-AM",
"source": "CoinDesk",
"symbol": "֏",
"country": "Armenia (Armenian Dram)"
},
"ANG": {
"endPointKey": "ANG",
"locale": "en-SX",
@ -293,6 +300,13 @@
"symbol": "lei",
"country": "Romania (Romanian Leu)"
},
"RSD": {
"endPointKey": "RSD",
"locale": "sr-RS",
"source": "CoinGecko",
"symbol": "DIN",
"country": "Serbia (Serbian Dinar)"
},
"RUB": {
"endPointKey": "RUB",
"locale": "ru-RU",

View file

@ -1,6 +1,5 @@
import DefaultPreference from 'react-native-default-preference';
import AsyncStorage from '@react-native-async-storage/async-storage';
import BigNumber from 'bignumber.js';
import DefaultPreference from 'react-native-default-preference';
import * as RNLocalize from 'react-native-localize';
import { FiatUnit, FiatUnitType, getFiatRate } from '../models/fiatUnit';
@ -30,60 +29,6 @@ let skipUpdateExchangeRate: boolean = false;
let currencyFormatter: Intl.NumberFormat | null = null;
let btcFormatter: Intl.NumberFormat | null = null;
// Initialize DefaultPreference with the correct group name
DefaultPreference.setName(GROUP_IO_BLUEWALLET);
/**
* Migration Function:
* Transfers data from AsyncStorage to DefaultPreference if present.
* DefaultPreference uses truly native preference storage which makes use of
* extensions easier.
* After migration, removes the data from AsyncStorage.
*/
async function migrateAsyncStorageToDefaultPreference(): Promise<void> {
try {
// Migrate Preferred Currency
const asyncPreferredCurrency = await AsyncStorage.getItem(PREFERRED_CURRENCY_STORAGE_KEY);
if (asyncPreferredCurrency) {
try {
const parsedCurrency = JSON.parse(asyncPreferredCurrency);
if (FiatUnit[parsedCurrency.endPointKey]) {
await DefaultPreference.set(PREFERRED_CURRENCY_STORAGE_KEY, parsedCurrency.endPointKey);
await DefaultPreference.set(PREFERRED_CURRENCY_LOCALE_STORAGE_KEY, parsedCurrency.locale.replace('-', '_'));
preferredFiatCurrency = FiatUnit[parsedCurrency.endPointKey];
}
} catch (error) {
console.error('Failed to parse preferred currency from AsyncStorage:', error);
} finally {
await AsyncStorage.removeItem(PREFERRED_CURRENCY_STORAGE_KEY);
await AsyncStorage.removeItem(PREFERRED_CURRENCY_LOCALE_STORAGE_KEY);
}
}
// Migrate Exchange Rates
const asyncExchangeRates = await AsyncStorage.getItem(EXCHANGE_RATES_STORAGE_KEY);
if (asyncExchangeRates) {
try {
const parsedRates = JSON.parse(asyncExchangeRates);
await DefaultPreference.set(EXCHANGE_RATES_STORAGE_KEY, asyncExchangeRates);
exchangeRates = parsedRates;
} catch (error) {
console.error('Failed to parse exchange rates from AsyncStorage:', error);
} finally {
} catch (error) {
console.error('Failed to parse exchange rates from AsyncStorage:', error);
} else {
// Remove from AsyncStorage only if migration was successful
await AsyncStorage.removeItem(EXCHANGE_RATES_STORAGE_KEY);
}
}
console.log('Migration from AsyncStorage to DefaultPreference completed.');
} catch (migrationError) {
console.error('Migration failed:', migrationError);
}
}
function getCurrencyFormatter(): Intl.NumberFormat {
if (
!currencyFormatter ||
@ -117,32 +62,27 @@ function getBTCFormatter(): Intl.NumberFormat {
}
async function setPreferredCurrency(item: FiatUnitType): Promise<void> {
try {
await DefaultPreference.set(PREFERRED_CURRENCY_STORAGE_KEY, item.endPointKey);
await DefaultPreference.set(PREFERRED_CURRENCY_LOCALE_STORAGE_KEY, item.locale.replace('-', '_'));
preferredFiatCurrency = item;
currencyFormatter = null;
btcFormatter = null;
} catch (error) {
console.error('Failed to set preferred currency:', error);
throw error;
}
await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
await DefaultPreference.set(PREFERRED_CURRENCY_STORAGE_KEY, JSON.stringify(item));
await DefaultPreference.set(PREFERRED_CURRENCY_LOCALE_STORAGE_KEY, item.locale.replace('-', '_'));
currencyFormatter = null;
btcFormatter = null;
}
async function updateExchangeRate(): Promise<void> {
if (skipUpdateExchangeRate) return;
if (Date.now() - lastTimeUpdateExchangeRateWasCalled <= 10000) {
// Simple debounce to prevent race conditions
// simple debounce so there's no race conditions
return;
}
lastTimeUpdateExchangeRateWasCalled = Date.now();
const lastUpdated = exchangeRates[LAST_UPDATED] as number | undefined;
if (lastUpdated && Date.now() - lastUpdated <= 30 * 60 * 1000) {
// Not updating too often
// not updating too often
return;
}
console.log('Updating exchange rate...');
console.log('updating exchange rate...');
try {
const rate = await getFiatRate(preferredFiatCurrency.endPointKey);
@ -152,22 +92,27 @@ async function updateExchangeRate(): Promise<void> {
try {
const exchangeRatesString = JSON.stringify(exchangeRates);
await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
await DefaultPreference.set(EXCHANGE_RATES_STORAGE_KEY, exchangeRatesString);
} catch (error) {
console.error('Failed to set exchange rates in DefaultPreference:', error);
await DefaultPreference.clear(EXCHANGE_RATES_STORAGE_KEY);
exchangeRates = { LAST_UPDATED_ERROR: false };
}
} catch (error) {
console.error('Failed to fetch fiat rate:', error);
try {
const ratesString = await DefaultPreference.get(EXCHANGE_RATES_STORAGE_KEY);
await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
const ratesValue = await DefaultPreference.get(EXCHANGE_RATES_STORAGE_KEY);
let ratesString: string | null = null;
if (typeof ratesValue === 'string') {
ratesString = ratesValue;
}
let rate;
if (ratesString) {
try {
rate = JSON.parse(ratesString);
} catch (parseError) {
console.error('Failed to parse exchange rates:', parseError);
await DefaultPreference.clear(EXCHANGE_RATES_STORAGE_KEY);
rate = {};
}
@ -178,7 +123,6 @@ async function updateExchangeRate(): Promise<void> {
exchangeRates.LAST_UPDATED_ERROR = true;
await DefaultPreference.set(EXCHANGE_RATES_STORAGE_KEY, JSON.stringify(rate));
} catch (storageError) {
console.error('Failed to handle exchange rate error:', storageError);
exchangeRates = { LAST_UPDATED_ERROR: true };
throw storageError;
}
@ -186,58 +130,61 @@ async function updateExchangeRate(): Promise<void> {
}
async function getPreferredCurrency(): Promise<FiatUnitType> {
try {
const preferredCurrencyString = await DefaultPreference.get(PREFERRED_CURRENCY_STORAGE_KEY);
if (preferredCurrencyString) {
try {
if (!FiatUnit[preferredCurrencyString]) {
throw new Error('Invalid Fiat Unit');
}
preferredFiatCurrency = FiatUnit[preferredCurrencyString];
} catch (error) {
console.error('Failed to parse preferred currency:', error);
await DefaultPreference.clear(PREFERRED_CURRENCY_STORAGE_KEY);
await DefaultPreference.clear(PREFERRED_CURRENCY_LOCALE_STORAGE_KEY);
await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
const preferredCurrencyValue = await DefaultPreference.get(PREFERRED_CURRENCY_STORAGE_KEY);
let preferredCurrency: string | null = null;
const deviceCurrencies = RNLocalize.getCurrencies();
if (deviceCurrencies[0] && FiatUnit[deviceCurrencies[0]]) {
preferredFiatCurrency = FiatUnit[deviceCurrencies[0]];
} else {
preferredFiatCurrency = FiatUnit.USD;
}
await setPreferredCurrency(preferredFiatCurrency);
if (typeof preferredCurrencyValue === 'string') {
preferredCurrency = preferredCurrencyValue;
}
if (preferredCurrency) {
let parsedPreferredCurrency;
try {
parsedPreferredCurrency = JSON.parse(preferredCurrency);
if (!FiatUnit[parsedPreferredCurrency.endPointKey]) {
throw new Error('Invalid Fiat Unit');
}
preferredFiatCurrency = FiatUnit[parsedPreferredCurrency.endPointKey];
} catch (error) {
await DefaultPreference.clear(PREFERRED_CURRENCY_STORAGE_KEY);
return preferredFiatCurrency;
const deviceCurrencies = RNLocalize.getCurrencies();
if (deviceCurrencies[0] && FiatUnit[deviceCurrencies[0]]) {
preferredFiatCurrency = FiatUnit[deviceCurrencies[0]];
} else {
preferredFiatCurrency = FiatUnit.USD;
}
}
// If no preferred currency is set, determine based on device settings
const deviceCurrencies = RNLocalize.getCurrencies();
if (deviceCurrencies[0] && FiatUnit[deviceCurrencies[0]]) {
preferredFiatCurrency = FiatUnit[deviceCurrencies[0]];
} else {
preferredFiatCurrency = FiatUnit.USD;
}
await setPreferredCurrency(preferredFiatCurrency);
return preferredFiatCurrency;
} catch (error) {
console.error('Failed to get preferred currency:', error);
// Fallback to USD in case of error
preferredFiatCurrency = FiatUnit.USD;
await setPreferredCurrency(preferredFiatCurrency);
await DefaultPreference.set(PREFERRED_CURRENCY_LOCALE_STORAGE_KEY, preferredFiatCurrency.locale.replace('-', '_'));
return preferredFiatCurrency;
}
const deviceCurrencies = RNLocalize.getCurrencies();
if (deviceCurrencies[0] && FiatUnit[deviceCurrencies[0]]) {
preferredFiatCurrency = FiatUnit[deviceCurrencies[0]];
} else {
preferredFiatCurrency = FiatUnit.USD;
}
return preferredFiatCurrency;
}
async function _restoreSavedExchangeRatesFromStorage(): Promise<void> {
try {
const ratesString = await DefaultPreference.get(EXCHANGE_RATES_STORAGE_KEY);
await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
const ratesValue = await DefaultPreference.get(EXCHANGE_RATES_STORAGE_KEY);
let ratesString: string | null = null;
if (typeof ratesValue === 'string') {
ratesString = ratesValue;
}
if (ratesString) {
try {
exchangeRates = JSON.parse(ratesString);
} catch (error) {
console.error('Failed to parse exchange rates:', error);
await DefaultPreference.clear(EXCHANGE_RATES_STORAGE_KEY);
exchangeRates = { LAST_UPDATED_ERROR: false };
await updateExchangeRate();
@ -246,7 +193,6 @@ async function _restoreSavedExchangeRatesFromStorage(): Promise<void> {
exchangeRates = { LAST_UPDATED_ERROR: false };
}
} catch (error) {
console.error('Failed to restore exchange rates:', error);
exchangeRates = { LAST_UPDATED_ERROR: false };
await updateExchangeRate();
}
@ -254,15 +200,25 @@ async function _restoreSavedExchangeRatesFromStorage(): Promise<void> {
async function _restoreSavedPreferredFiatCurrencyFromStorage(): Promise<void> {
try {
const storedCurrencyString = await DefaultPreference.get(PREFERRED_CURRENCY_STORAGE_KEY);
if (!storedCurrencyString) throw new Error('No Preferred Fiat selected');
await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
const storedCurrencyValue = await DefaultPreference.get(PREFERRED_CURRENCY_STORAGE_KEY);
let storedCurrency: string | null = null;
if (typeof storedCurrencyValue === 'string') {
storedCurrency = storedCurrencyValue;
}
if (!storedCurrency) throw new Error('No Preferred Fiat selected');
let parsedCurrency;
try {
preferredFiatCurrency = FiatUnit[storedCurrencyString];
parsedCurrency = JSON.parse(storedCurrency);
if (!FiatUnit[parsedCurrency.endPointKey]) {
throw new Error('Invalid Fiat Unit');
}
preferredFiatCurrency = FiatUnit[parsedCurrency.endPointKey];
} catch (error) {
console.error('Failed to parse stored currency:', error);
await DefaultPreference.clear(PREFERRED_CURRENCY_STORAGE_KEY);
await DefaultPreference.clear(PREFERRED_CURRENCY_LOCALE_STORAGE_KEY);
const deviceCurrencies = RNLocalize.getCurrencies();
if (deviceCurrencies[0] && FiatUnit[deviceCurrencies[0]]) {
@ -270,29 +226,32 @@ async function _restoreSavedPreferredFiatCurrencyFromStorage(): Promise<void> {
} else {
preferredFiatCurrency = FiatUnit.USD;
}
await setPreferredCurrency(preferredFiatCurrency);
}
} catch (error) {
console.error('Failed to restore preferred fiat currency:', error);
const deviceCurrencies = RNLocalize.getCurrencies();
if (deviceCurrencies[0] && FiatUnit[deviceCurrencies[0]]) {
preferredFiatCurrency = FiatUnit[deviceCurrencies[0]];
} else {
preferredFiatCurrency = FiatUnit.USD;
}
await setPreferredCurrency(preferredFiatCurrency);
}
}
async function isRateOutdated(): Promise<boolean> {
try {
const rateString = await DefaultPreference.get(EXCHANGE_RATES_STORAGE_KEY);
await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
const rateValue = await DefaultPreference.get(EXCHANGE_RATES_STORAGE_KEY);
let rateString: string | null = null;
if (typeof rateValue === 'string') {
rateString = rateValue;
}
let rate;
if (rateString) {
try {
rate = JSON.parse(rateString);
} catch (parseError) {
console.error('Failed to parse exchange rates:', parseError);
await DefaultPreference.clear(EXCHANGE_RATES_STORAGE_KEY);
rate = {};
await updateExchangeRate();
@ -301,8 +260,7 @@ async function isRateOutdated(): Promise<boolean> {
rate = {};
}
return rate.LAST_UPDATED_ERROR || Date.now() - (rate[LAST_UPDATED] || 0) >= 31 * 60 * 1000;
} catch (error) {
console.error('Failed to determine if rate is outdated:', error);
} catch {
return true;
}
}
@ -313,12 +271,12 @@ async function restoreSavedPreferredFiatCurrencyAndExchangeFromStorage(): Promis
}
async function initCurrencyDaemon(clearLastUpdatedTime: boolean = false): Promise<void> {
await restoreSavedPreferredFiatCurrencyAndExchangeFromStorage();
await _restoreSavedExchangeRatesFromStorage();
await _restoreSavedPreferredFiatCurrencyFromStorage();
if (clearLastUpdatedTime) {
exchangeRates[LAST_UPDATED] = 0;
lastTimeUpdateExchangeRateWasCalled = 0;
await DefaultPreference.set(EXCHANGE_RATES_STORAGE_KEY, JSON.stringify(exchangeRates));
}
await updateExchangeRate();
@ -343,12 +301,12 @@ function satoshiToLocalCurrency(satoshi: number, format: boolean = true): string
formattedAmount = convertedAmount.toPrecision(2);
}
if (!format) return formattedAmount;
if (format === false) return formattedAmount;
try {
return getCurrencyFormatter().format(Number(formattedAmount));
} catch (error) {
console.error('Failed to format currency:', error);
console.error(error);
return formattedAmount;
}
}
@ -360,13 +318,19 @@ function BTCToLocalCurrency(bitcoin: BigNumber.Value): string {
async function mostRecentFetchedRate(): Promise<CurrencyRate> {
try {
const currencyInformationString = await DefaultPreference.get(EXCHANGE_RATES_STORAGE_KEY);
await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
const currencyInfoValue = await DefaultPreference.get(EXCHANGE_RATES_STORAGE_KEY);
let currencyInformationString: string | null = null;
if (typeof currencyInfoValue === 'string') {
currencyInformationString = currencyInfoValue;
}
let currencyInformation;
if (currencyInformationString) {
try {
currencyInformation = JSON.parse(currencyInformationString);
} catch (parseError) {
console.error('Failed to parse exchange rates:', parseError);
await DefaultPreference.clear(EXCHANGE_RATES_STORAGE_KEY);
currencyInformation = {};
await updateExchangeRate();
@ -380,8 +344,7 @@ async function mostRecentFetchedRate(): Promise<CurrencyRate> {
LastUpdated: currencyInformation[LAST_UPDATED] ? new Date(currencyInformation[LAST_UPDATED]) : null,
Rate: rate ? getCurrencyFormatter().format(rate) : '...',
};
} catch (error) {
console.error('Failed to fetch most recent rate:', error);
} catch {
return {
LastUpdated: null,
Rate: null,
@ -417,7 +380,7 @@ function formatBTC(btc: BigNumber.Value): string {
try {
return getBTCFormatter().format(Number(btc));
} catch (error) {
console.error('Failed to format BTC:', error);
console.error(error);
return new BigNumber(btc).toFixed(8);
}
}
@ -455,5 +418,4 @@ export {
setPreferredCurrency,
updateExchangeRate,
formatBTC,
migrateAsyncStorageToDefaultPreference,
};

View file

@ -9,7 +9,7 @@ import { GROUP_IO_BLUEWALLET } from '../blue_modules/currency';
export const getLNDHub = async (): Promise<string | undefined> => {
try {
await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
let value = await DefaultPreference.get(BlueApp.LNDHUB);
let value = await DefaultPreference.get(BlueApp.LNDHUB) as string | null;
// If not found, check AsyncStorage and migrate it to DefaultPreference
if (!value) {

View file

@ -155,7 +155,7 @@
B4D0B2682C1DED67006B6B1B /* ReceiveMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4D0B2672C1DED67006B6B1B /* ReceiveMethod.swift */; };
B4EE583C226703320003363C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B40D4E35225841ED00428FCC /* Assets.xcassets */; };
B4EFF73B2C3F6C5E0095D655 /* MockData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4EFF73A2C3F6C5E0095D655 /* MockData.swift */; };
C978A716948AB7DEC5B6F677 /* (null) in Frameworks */ = {isa = PBXBuildFile; };
C978A716948AB7DEC5B6F677 /* BuildFile in Frameworks */ = {isa = PBXBuildFile; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -416,7 +416,7 @@
files = (
782F075B5DD048449E2DECE9 /* libz.tbd in Frameworks */,
764B49B1420D4AEB8109BF62 /* libsqlite3.0.tbd in Frameworks */,
C978A716948AB7DEC5B6F677 /* (null) in Frameworks */,
C978A716948AB7DEC5B6F677 /* BuildFile in Frameworks */,
17CDA0718F42DB2CE856C872 /* libPods-BlueWallet.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;

View file

@ -1,108 +1 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1500"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B40D4E2F225841EC00428FCC"
BuildableName = "BlueWalletWatch.app"
BlueprintName = "BlueWalletWatch"
ReferencedContainer = "container:BlueWallet.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "BlueWallet.app"
BlueprintName = "BlueWallet"
ReferencedContainer = "container:BlueWallet.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B47B21E82B2128B8001F6690"
BuildableName = "BlueWalletUITests.xctest"
BlueprintName = "BlueWalletUITests"
ReferencedContainer = "container:BlueWallet.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES"
launchAutomaticallySubstyle = "8"
notificationPayloadFile = "BlueWalletWatch Extension/PushNotificationPayload.apns">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B40D4E2F225841EC00428FCC"
BuildableName = "BlueWalletWatch.app"
BlueprintName = "BlueWalletWatch"
ReferencedContainer = "container:BlueWallet.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"
launchAutomaticallySubstyle = "8"
notificationPayloadFile = "BlueWalletWatch Extension/PushNotificationPayload.apns">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B40D4E2F225841EC00428FCC"
BuildableName = "BlueWalletWatch.app"
BlueprintName = "BlueWalletWatch"
ReferencedContainer = "container:BlueWallet.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
use

View file

@ -70,7 +70,7 @@ export const removeBlockExplorer = async (): Promise<boolean> => {
export const getBlockExplorerUrl = async (): Promise<string> => {
try {
const url = await DefaultPreference.get(BLOCK_EXPLORER_STORAGE_KEY);
const url = (await DefaultPreference.get(BLOCK_EXPLORER_STORAGE_KEY)) as string | null;
return url ?? BLOCK_EXPLORERS.default.url;
} catch (error) {
console.error('Error getting block explorer:', error);

8
package-lock.json generated
View file

@ -65,7 +65,7 @@
"react-native-blue-crypto": "github:BlueWallet/react-native-blue-crypto#3cb5442",
"react-native-camera-kit": "13.0.0",
"react-native-crypto": "2.2.0",
"react-native-default-preference": "1.4.4",
"react-native-default-preference": "https://github.com/BlueWallet/react-native-default-preference.git#258a3f07a36b86d34d4d1b682e928bab5524cc8c",
"react-native-device-info": "13.2.0",
"react-native-document-picker": "9.3.1",
"react-native-draggable-flatlist": "github:BlueWallet/react-native-draggable-flatlist#3a61627",
@ -20579,9 +20579,9 @@
}
},
"node_modules/react-native-default-preference": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/react-native-default-preference/-/react-native-default-preference-1.4.4.tgz",
"integrity": "sha512-h0vtgiSKws3UmMRJykXAVM4ne1SgfoocUcoBD19ewRpQd6wqurE0HJRQGrSxcHK5LdKE7QPSIB1VX3YGIVS8Jg==",
"version": "1.5.1",
"resolved": "git+ssh://git@github.com/BlueWallet/react-native-default-preference.git#258a3f07a36b86d34d4d1b682e928bab5524cc8c",
"integrity": "sha512-29z1QFauCI2UprTIfiB5wLvUTf46+ogiP/S0FbHvFjDPohAm+mdB4+sO1rzhdmbSbKCSuX9O9micBhyOh867ew==",
"license": "MIT",
"peerDependencies": {
"react-native": ">=0.47.0"

View file

@ -129,7 +129,7 @@
"react-native-blue-crypto": "github:BlueWallet/react-native-blue-crypto#3cb5442",
"react-native-camera-kit": "13.0.0",
"react-native-crypto": "2.2.0",
"react-native-default-preference": "1.4.4",
"react-native-default-preference": "https://github.com/BlueWallet/react-native-default-preference.git#258a3f07a36b86d34d4d1b682e928bab5524cc8c",
"react-native-device-info": "13.2.0",
"react-native-document-picker": "9.3.1",
"react-native-draggable-flatlist": "github:BlueWallet/react-native-draggable-flatlist#3a61627",

View file

@ -1,4 +1,4 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import DefaultPreference from 'react-native-default-preference';
import assert from 'assert';
import {
@ -8,24 +8,34 @@ import {
LAST_UPDATED,
PREFERRED_CURRENCY_STORAGE_KEY,
setPreferredCurrency,
GROUP_IO_BLUEWALLET,
} from '../../blue_modules/currency';
import { FiatUnit } from '../../models/fiatUnit';
jest.setTimeout(90 * 1000);
describe('currency', () => {
it('fetches exchange rate and saves to AsyncStorage', async () => {
beforeAll(async () => {
await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
});
afterEach(async () => {
await DefaultPreference.clearAll();
});
it('fetches exchange rate and saves to DefaultPreference', async () => {
await initCurrencyDaemon();
let cur = await AsyncStorage.getItem(EXCHANGE_RATES_STORAGE_KEY);
cur = JSON.parse(cur);
let curString = await DefaultPreference.get(EXCHANGE_RATES_STORAGE_KEY);
let cur = JSON.parse(curString || '{}');
assert.ok(Number.isInteger(cur[LAST_UPDATED]));
assert.ok(cur[LAST_UPDATED] > 0);
assert.ok(cur.BTC_USD > 0);
// now, setting other currency as default
await AsyncStorage.setItem(PREFERRED_CURRENCY_STORAGE_KEY, JSON.stringify(FiatUnit.JPY));
await DefaultPreference.set(PREFERRED_CURRENCY_STORAGE_KEY, JSON.stringify(FiatUnit.JPY));
await initCurrencyDaemon(true);
cur = JSON.parse(await AsyncStorage.getItem(EXCHANGE_RATES_STORAGE_KEY));
curString = await DefaultPreference.get(EXCHANGE_RATES_STORAGE_KEY);
cur = JSON.parse(curString || '{}');
assert.ok(cur.BTC_JPY > 0);
// now setting with a proper setter
@ -33,25 +43,29 @@ describe('currency', () => {
await initCurrencyDaemon(true);
const preferred = await getPreferredCurrency();
assert.strictEqual(preferred.endPointKey, 'EUR');
cur = JSON.parse(await AsyncStorage.getItem(EXCHANGE_RATES_STORAGE_KEY));
curString = await DefaultPreference.get(EXCHANGE_RATES_STORAGE_KEY);
cur = JSON.parse(curString || '{}');
assert.ok(cur.BTC_EUR > 0);
// test Yadio rate source
await setPreferredCurrency(FiatUnit.ARS);
await initCurrencyDaemon(true);
cur = JSON.parse(await AsyncStorage.getItem(EXCHANGE_RATES_STORAGE_KEY));
curString = await DefaultPreference.get(EXCHANGE_RATES_STORAGE_KEY);
cur = JSON.parse(curString || '{}');
assert.ok(cur.BTC_ARS > 0);
// test YadioConvert rate source
await setPreferredCurrency(FiatUnit.LBP);
await initCurrencyDaemon(true);
cur = JSON.parse(await AsyncStorage.getItem(EXCHANGE_RATES_STORAGE_KEY));
curString = await DefaultPreference.get(EXCHANGE_RATES_STORAGE_KEY);
cur = JSON.parse(curString || '{}');
assert.ok(cur.BTC_LBP > 0);
// test Exir rate source
await setPreferredCurrency(FiatUnit.IRT);
await initCurrencyDaemon(true);
cur = JSON.parse(await AsyncStorage.getItem(EXCHANGE_RATES_STORAGE_KEY));
curString = await DefaultPreference.get(EXCHANGE_RATES_STORAGE_KEY);
cur = JSON.parse(curString || '{}');
assert.ok(cur.BTC_IRT > 0);
});
});

View file

@ -72,9 +72,81 @@ jest.mock('react-native-quick-actions', () => {
});
jest.mock('react-native-default-preference', () => {
let mockPreferences = {};
let currentSuiteName = 'default';
const getSuite = name => {
if (!mockPreferences[name]) {
mockPreferences[name] = {};
}
return mockPreferences[name];
};
return {
setName: jest.fn(),
set: jest.fn(),
setName: jest.fn(name => {
currentSuiteName = name;
if (!mockPreferences[name]) {
mockPreferences[name] = {};
}
return Promise.resolve();
}),
getName: jest.fn(() => {
return Promise.resolve(currentSuiteName);
}),
get: jest.fn(key => {
const suite = getSuite(currentSuiteName);
return Promise.resolve(Object.prototype.hasOwnProperty.call(suite, key) ? suite[key] : null);
}),
set: jest.fn((key, value) => {
const suite = getSuite(currentSuiteName);
suite[key] = value;
return Promise.resolve();
}),
clear: jest.fn(key => {
const suite = getSuite(currentSuiteName);
delete suite[key];
return Promise.resolve();
}),
getMultiple: jest.fn(keys => {
const suite = getSuite(currentSuiteName);
const values = keys.map(key => (Object.prototype.hasOwnProperty.call(suite, key) ? suite[key] : null));
return Promise.resolve(values);
}),
setMultiple: jest.fn(keyValuePairs => {
const suite = getSuite(currentSuiteName);
Object.entries(keyValuePairs).forEach(([key, value]) => {
suite[key] = value;
});
return Promise.resolve();
}),
clearMultiple: jest.fn(keys => {
const suite = getSuite(currentSuiteName);
keys.forEach(key => delete suite[key]);
return Promise.resolve();
}),
getAll: jest.fn(() => {
const suite = getSuite(currentSuiteName);
return Promise.resolve({ ...suite });
}),
clearAll: jest.fn(() => {
mockPreferences[currentSuiteName] = {};
return Promise.resolve();
}),
reset: jest.fn(() => {
mockPreferences = {};
currentSuiteName = 'default'; // Reset the current suite name
return Promise.resolve();
}),
};
});