mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-03-15 11:59:21 +01:00
FIX: transactions list screen would not always update with new transactions
This commit is contained in:
parent
80fb4a74a8
commit
85cb6c1287
6 changed files with 104 additions and 12 deletions
|
@ -362,6 +362,7 @@ export const TransactionListItem: React.FC<TransactionListItemProps> = React.mem
|
||||||
rightTitle={rowTitle}
|
rightTitle={rowTitle}
|
||||||
rightTitleStyle={rowTitleStyle}
|
rightTitleStyle={rowTitleStyle}
|
||||||
containerStyle={combinedStyle}
|
containerStyle={combinedStyle}
|
||||||
|
testID="TransactionListItem"
|
||||||
/>
|
/>
|
||||||
</ToolTipMenu>
|
</ToolTipMenu>
|
||||||
);
|
);
|
||||||
|
|
|
@ -367,12 +367,17 @@ const WalletDetails: React.FC = () => {
|
||||||
const purgeTransactions = async () => {
|
const purgeTransactions = async () => {
|
||||||
if (backdoorPressed < 10) return setBackdoorPressed(backdoorPressed + 1);
|
if (backdoorPressed < 10) return setBackdoorPressed(backdoorPressed + 1);
|
||||||
setBackdoorPressed(0);
|
setBackdoorPressed(0);
|
||||||
const msg = 'Transactions purged. Pls go to main screen and back to rerender screen';
|
const msg = 'Transactions & balances purged. Pls go to main screen and back to rerender screen';
|
||||||
|
|
||||||
if (wallet.type === HDSegwitBech32Wallet.type) {
|
if (wallet.type === HDSegwitBech32Wallet.type) {
|
||||||
wallet._txs_by_external_index = {};
|
wallet._txs_by_external_index = {};
|
||||||
wallet._txs_by_internal_index = {};
|
wallet._txs_by_internal_index = {};
|
||||||
presentAlert({ message: msg });
|
presentAlert({ message: msg });
|
||||||
|
|
||||||
|
wallet._balances_by_external_index = {};
|
||||||
|
wallet._balances_by_internal_index = {};
|
||||||
|
wallet._lastTxFetch = 0;
|
||||||
|
wallet._lastBalanceFetch = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error: Need to fix later
|
// @ts-expect-error: Need to fix later
|
||||||
|
@ -381,6 +386,15 @@ const WalletDetails: React.FC = () => {
|
||||||
wallet._hdWalletInstance._txs_by_external_index = {};
|
wallet._hdWalletInstance._txs_by_external_index = {};
|
||||||
// @ts-expect-error: Need to fix later
|
// @ts-expect-error: Need to fix later
|
||||||
wallet._hdWalletInstance._txs_by_internal_index = {};
|
wallet._hdWalletInstance._txs_by_internal_index = {};
|
||||||
|
|
||||||
|
// @ts-expect-error: Need to fix later
|
||||||
|
wallet._hdWalletInstance._balances_by_external_index = {};
|
||||||
|
// @ts-expect-error: Need to fix later
|
||||||
|
wallet._hdWalletInstance._balances_by_internal_index = {};
|
||||||
|
// @ts-expect-error: Need to fix later
|
||||||
|
wallet._hdWalletInstance._lastTxFetch = 0;
|
||||||
|
// @ts-expect-error: Need to fix later
|
||||||
|
wallet._hdWalletInstance._lastBalanceFetch = 0;
|
||||||
presentAlert({ message: msg });
|
presentAlert({ message: msg });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -528,7 +542,7 @@ const WalletDetails: React.FC = () => {
|
||||||
</View>
|
</View>
|
||||||
</>
|
</>
|
||||||
<>
|
<>
|
||||||
<Text onPress={purgeTransactions} style={[styles.textLabel2, stylesHook.textLabel2]}>
|
<Text onPress={purgeTransactions} style={[styles.textLabel2, stylesHook.textLabel2]} testID="PurgeBackdoorButton">
|
||||||
{loc.transactions.transactions_count.toLowerCase()}
|
{loc.transactions.transactions_count.toLowerCase()}
|
||||||
</Text>
|
</Text>
|
||||||
<BlueText>{wallet.getTransactions().length}</BlueText>
|
<BlueText>{wallet.getTransactions().length}</BlueText>
|
||||||
|
|
|
@ -119,7 +119,9 @@ const WalletTransactions: React.FC<WalletTransactionsProps> = ({ route }) => {
|
||||||
const txs = wallet.getTransactions();
|
const txs = wallet.getTransactions();
|
||||||
txs.sort((a: { received: string }, b: { received: string }) => +new Date(b.received) - +new Date(a.received));
|
txs.sort((a: { received: string }, b: { received: string }) => +new Date(b.received) - +new Date(a.received));
|
||||||
return txs;
|
return txs;
|
||||||
}, [wallet]);
|
// we use `wallet.getLastTxFetch()` to tell if txs list changed
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [wallet, wallet?.getLastTxFetch()]);
|
||||||
|
|
||||||
const getTransactions = useCallback((lmt = Infinity): Transaction[] => sortedTransactions.slice(0, lmt), [sortedTransactions]);
|
const getTransactions = useCallback((lmt = Infinity): Transaction[] => sortedTransactions.slice(0, lmt), [sortedTransactions]);
|
||||||
|
|
||||||
|
@ -171,7 +173,6 @@ const WalletTransactions: React.FC<WalletTransactionsProps> = ({ route }) => {
|
||||||
setFetchFailures(0);
|
setFetchFailures(0);
|
||||||
const newTimestamp = Date.now();
|
const newTimestamp = Date.now();
|
||||||
setLastFetchTimestamp(newTimestamp);
|
setLastFetchTimestamp(newTimestamp);
|
||||||
wallet._lastTxFetch = newTimestamp;
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setFetchFailures(prev => {
|
setFetchFailures(prev => {
|
||||||
const newFailures = prev + 1;
|
const newFailures = prev + 1;
|
||||||
|
@ -290,11 +291,6 @@ const WalletTransactions: React.FC<WalletTransactionsProps> = ({ route }) => {
|
||||||
index,
|
index,
|
||||||
});
|
});
|
||||||
|
|
||||||
const listData: Transaction[] = useMemo(() => {
|
|
||||||
const transactions = getTransactions(limit);
|
|
||||||
return transactions;
|
|
||||||
}, [getTransactions, limit]);
|
|
||||||
|
|
||||||
const renderItem = useCallback(
|
const renderItem = useCallback(
|
||||||
// eslint-disable-next-line react/no-unused-prop-types
|
// eslint-disable-next-line react/no-unused-prop-types
|
||||||
({ item }: { item: Transaction }) => {
|
({ item }: { item: Transaction }) => {
|
||||||
|
@ -521,6 +517,7 @@ const WalletTransactions: React.FC<WalletTransactionsProps> = ({ route }) => {
|
||||||
styles.refreshIndicatorBackground,
|
styles.refreshIndicatorBackground,
|
||||||
{ backgroundColor: wallet ? WalletGradient.headerColorFor(wallet.type) : colors.background },
|
{ backgroundColor: wallet ? WalletGradient.headerColorFor(wallet.type) : colors.background },
|
||||||
]}
|
]}
|
||||||
|
testID="TransactionsListView"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FlatList<Transaction>
|
<FlatList<Transaction>
|
||||||
|
@ -529,7 +526,7 @@ const WalletTransactions: React.FC<WalletTransactionsProps> = ({ route }) => {
|
||||||
onEndReachedThreshold={0.3}
|
onEndReachedThreshold={0.3}
|
||||||
onEndReached={loadMoreTransactions}
|
onEndReached={loadMoreTransactions}
|
||||||
ListFooterComponent={renderListFooterComponent}
|
ListFooterComponent={renderListFooterComponent}
|
||||||
data={listData}
|
data={getTransactions(limit)}
|
||||||
extraData={wallet}
|
extraData={wallet}
|
||||||
keyExtractor={_keyExtractor}
|
keyExtractor={_keyExtractor}
|
||||||
renderItem={renderItem}
|
renderItem={renderItem}
|
||||||
|
@ -544,7 +541,7 @@ const WalletTransactions: React.FC<WalletTransactionsProps> = ({ route }) => {
|
||||||
ListHeaderComponent={ListHeaderComponent}
|
ListHeaderComponent={ListHeaderComponent}
|
||||||
ListEmptyComponent={
|
ListEmptyComponent={
|
||||||
<ScrollView style={[styles.flex, { backgroundColor: colors.background }]} contentContainerStyle={styles.scrollViewContent}>
|
<ScrollView style={[styles.flex, { backgroundColor: colors.background }]} contentContainerStyle={styles.scrollViewContent}>
|
||||||
<Text numberOfLines={0} style={styles.emptyTxs}>
|
<Text numberOfLines={0} style={styles.emptyTxs} testID="TransactionsListEmpty">
|
||||||
{(isLightning() && loc.wallets.list_empty_txs1_lightning) || loc.wallets.list_empty_txs1}
|
{(isLightning() && loc.wallets.list_empty_txs1_lightning) || loc.wallets.list_empty_txs1}
|
||||||
</Text>
|
</Text>
|
||||||
{isLightning() && <Text style={styles.emptyTxsLightning}>{loc.wallets.list_empty_txs2_lightning}</Text>}
|
{isLightning() && <Text style={styles.emptyTxsLightning}>{loc.wallets.list_empty_txs2_lightning}</Text>}
|
||||||
|
|
|
@ -12,8 +12,17 @@ import {
|
||||||
tapAndTapAgainIfTextIsNotVisible,
|
tapAndTapAgainIfTextIsNotVisible,
|
||||||
tapIfTextPresent,
|
tapIfTextPresent,
|
||||||
waitForId,
|
waitForId,
|
||||||
|
countElements,
|
||||||
} from './helperz';
|
} from './helperz';
|
||||||
|
|
||||||
|
// if loglevel is set to `error`, this kind of logging will still get through
|
||||||
|
console.warn = console.log = (...args) => {
|
||||||
|
let output = '';
|
||||||
|
args.map(arg => (output += String(arg)));
|
||||||
|
|
||||||
|
process.stdout.write(output + '\n');
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* in this suite each test requires that there is one specific wallet present, thus, we import it
|
* in this suite each test requires that there is one specific wallet present, thus, we import it
|
||||||
* before anything else.
|
* before anything else.
|
||||||
|
@ -27,7 +36,7 @@ beforeAll(async () => {
|
||||||
// reinstalling the app just for any case to clean up app's storage
|
// reinstalling the app just for any case to clean up app's storage
|
||||||
await device.launchApp({ delete: true });
|
await device.launchApp({ delete: true });
|
||||||
|
|
||||||
console.log('before all - importing bip48...');
|
console.log('before all - importing bip84...');
|
||||||
await helperImportWallet(process.env.HD_MNEMONIC_BIP84, 'HDsegwitBech32', 'Imported HD SegWit (BIP84 Bech32 Native)', '0.00105526');
|
await helperImportWallet(process.env.HD_MNEMONIC_BIP84, 'HDsegwitBech32', 'Imported HD SegWit (BIP84 Bech32 Native)', '0.00105526');
|
||||||
console.log('...imported!');
|
console.log('...imported!');
|
||||||
await device.pressBack();
|
await device.pressBack();
|
||||||
|
@ -711,4 +720,54 @@ describe('BlueWallet UI Tests - import BIP84 wallet', () => {
|
||||||
|
|
||||||
process.env.TRAVIS && require('fs').writeFileSync(lockFile, '1');
|
process.env.TRAVIS && require('fs').writeFileSync(lockFile, '1');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('can purge txs and balance, then refetch data from tx list screen and see data on screen update', async () => {
|
||||||
|
const lockFile = '/tmp/travislock.' + hashIt('t24');
|
||||||
|
if (process.env.TRAVIS) {
|
||||||
|
if (require('fs').existsSync(lockFile)) return console.warn('skipping', JSON.stringify('t24'), 'as it previously passed on Travis');
|
||||||
|
}
|
||||||
|
if (!process.env.HD_MNEMONIC_BIP84) {
|
||||||
|
console.error('process.env.HD_MNEMONIC_BIP84 not set, skipped');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await device.launchApp({ newInstance: true });
|
||||||
|
// go inside the wallet
|
||||||
|
await element(by.text('Imported HD SegWit (BIP84 Bech32 Native)')).tap();
|
||||||
|
await element(by.id('WalletDetails')).tap();
|
||||||
|
|
||||||
|
// tapping backdoor button to purge txs and balance:
|
||||||
|
for (let c = 0; c <= 10; c++) {
|
||||||
|
await element(by.id('PurgeBackdoorButton')).tap();
|
||||||
|
await sleep(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
await waitForText('OK');
|
||||||
|
await tapIfTextPresent('OK');
|
||||||
|
|
||||||
|
if (device.getPlatform() === 'ios') {
|
||||||
|
console.warn('rest of the test is Android only, skipped');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await device.pressBack();
|
||||||
|
|
||||||
|
// asserting there are no transactions and balance is 0:
|
||||||
|
|
||||||
|
await expect(element(by.id('WalletBalance'))).toHaveText('0');
|
||||||
|
await waitForId('TransactionsListEmpty');
|
||||||
|
assert.strictEqual(await countElements('TransactionListItem'), 0);
|
||||||
|
|
||||||
|
await element(by.id('TransactionsListView')).swipe('down', 'slow'); // pul-to-refresh
|
||||||
|
|
||||||
|
// asserting balance and txs loaded:
|
||||||
|
await waitForText('0.00105526'); // the wait inside allows network request to propagate
|
||||||
|
await waitFor(element(by.id('TransactionsListEmpty')))
|
||||||
|
.not.toBeVisible()
|
||||||
|
.withTimeout(25_000);
|
||||||
|
await expect(element(by.id('WalletBalance'))).toHaveText('0.00105526');
|
||||||
|
await expect(element(by.id('TransactionsListEmpty'))).not.toBeVisible();
|
||||||
|
|
||||||
|
assert.ok((await countElements('TransactionListItem')) >= 3); // 3 is arbitrary, real txs on screen depend on screen size
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,13 @@
|
||||||
import { hashIt, helperDeleteWallet, helperImportWallet, sleep, waitForId } from './helperz';
|
import { hashIt, helperDeleteWallet, helperImportWallet, sleep, waitForId } from './helperz';
|
||||||
|
|
||||||
|
// if loglevel is set to `error`, this kind of logging will still get through
|
||||||
|
console.warn = console.log = (...args) => {
|
||||||
|
let output = '';
|
||||||
|
args.map(arg => (output += String(arg)));
|
||||||
|
|
||||||
|
process.stdout.write(output + '\n');
|
||||||
|
};
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
// reinstalling the app just for any case to clean up app's storage
|
// reinstalling the app just for any case to clean up app's storage
|
||||||
await device.launchApp({ delete: true });
|
await device.launchApp({ delete: true });
|
||||||
|
|
|
@ -228,3 +228,16 @@ export async function tapIfTextPresent(text) {
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
// no need to check for visibility, just silently ignore exception if such testID is not present
|
// no need to check for visibility, just silently ignore exception if such testID is not present
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function countElements(testId) {
|
||||||
|
let count = 0;
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
await expect(element(by.id(testId)).atIndex(count)).toExist();
|
||||||
|
count++;
|
||||||
|
} catch (_) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue