diff --git a/assets/translations/fr.json b/assets/translations/fr.json index 57056c4..bfe26e6 100644 --- a/assets/translations/fr.json +++ b/assets/translations/fr.json @@ -148,7 +148,7 @@ "seeAWallet": "Voir un portefeuille", "mustWaitXBeforeCertify": "Vous devez attendre\n{} avant\nde pouvoir certifier", "mustConfirmHisIdentity": "Cette personne doit confirmer\nson identité avant de pouvoir\nêtre certifié", - "canRenewCertInX": "Vous pourrez renouveller\ncette certification\ndans {}", + "canRenewCertInX": "Vous pourrez renouveler\ncette certification\ndans {}", "executeATransfer": "Effectuer un virement", "executeTheTransfer": "Effectuer le virement", "doATransfer": "Faire un\nvirement", diff --git a/integration_test/cert_state.dart b/integration_test/cert_state.dart new file mode 100644 index 0000000..d3e589a --- /dev/null +++ b/integration_test/cert_state.dart @@ -0,0 +1,59 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:gecko/globals.dart'; +import 'package:gecko/models/widgets_keys.dart'; +import 'package:integration_test/integration_test.dart'; +import 'package:gecko/main.dart' as app; +import 'general_actions.dart'; +import 'tests_utility.dart'; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + testWidgets('Gecko complete', (tester) async { + app.main(); + await tester.pumpAndSettle(const Duration(seconds: 1)); + + // Change Duniter endpoint to local + await changeNode(tester); + + // Delete all existing chests is exists + await deleteAllWallets(tester); + + // Restore the test chest + await restoreChest(tester); + + // Go wallet 5 view + await goKey(tester, keyOpenSearch); + await enterText(tester, keySearchField, test5.address); + await goKey(tester, keyConfirmSearch); + await waitFor(tester, test5.shortAddress()); + await goKey(tester, keySearchResult(test5.address)); + await waitFor(tester, 'Certifier'); + await waitFor(tester, 'Vous devez ', reverse: true); + await waitFor(tester, 'Vous pourrez renouveler ', reverse: true); + + // Background pay 25 + await pay(tester, + fromAddress: test1.address, destAddress: test5.address, amount: 25); + await waitFor(tester, '25.0 $currencyName'); + await spawnBlock(tester); + await waitFor(tester, '22.0 $currencyName'); + await certify(tester, + fromAddress: test1.address, destAddress: test5.address); + await waitFor(tester, '1', exactMatch: true); + await confirmIdentity(tester, fromAddress: test5.address, name: test5.name); + await spawnBlock(tester, number: 10); + await certify(tester, + fromAddress: test2.address, destAddress: test5.address); + await waitFor(tester, '2', exactMatch: true); + await certify(tester, + fromAddress: test3.address, destAddress: test5.address); + await waitFor(tester, '3', exactMatch: true); + await certify(tester, + fromAddress: test4.address, destAddress: test5.address); + await waitFor(tester, '4', exactMatch: true); + await pay(tester, + fromAddress: test2.address, destAddress: test5.address, amount: 40); + await waitFor(tester, '62.0 $currencyName'); + }); +} diff --git a/integration_test/gecko_complete.dart b/integration_test/gecko_complete.dart index 7c7c3a7..320577a 100644 --- a/integration_test/gecko_complete.dart +++ b/integration_test/gecko_complete.dart @@ -1,11 +1,9 @@ -import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:gecko/globals.dart'; import 'package:gecko/models/widgets_keys.dart'; import 'package:integration_test/integration_test.dart'; import 'package:gecko/main.dart' as app; +import 'general_actions.dart'; import 'tests_utility.dart'; void main() { @@ -32,97 +30,12 @@ void main() { }); } -Future changeNode(WidgetTester tester) async { - final ipAddress = dotenv.env['ip_address'] ?? '127.0.0.1'; - log.d('ip address: $ipAddress'); - - await goKey(tester, keyDrawerMenu); - await goKey(tester, keyParameters); - await goKey(tester, keySelectDuniterNodeDropDown, duration: 5); - await goKey(tester, keySelectDuniterNode('Personnalisé'), selectLast: true); - await enterText(tester, keyCustomDuniterEndpoint, 'ws://$ipAddress:9944'); - await goKey(tester, keyConnectToEndpoint); - await isIconPresent(tester, Icons.add_card_sharp, - timeout: const Duration(seconds: 8)); - await goBack(tester); -} - -Future deleteAllWallets(WidgetTester tester) async { - if (await isPresent(tester, 'Rechercher')) { - await goKey(tester, keyDrawerMenu); - await goKey(tester, keyParameters); - await goKey(tester, keyDeleteAllWallets); - await goKey(tester, keyConfirm); - await tester.pumpAndSettle(); - } -} - -Future restoreChest(WidgetTester tester) async { - // Copy test mnemonic in clipboard - Clipboard.setData(const ClipboardData( - text: - 'pipe paddle ketchup filter life ice feel embody glide quantum ride usage')); - - // Open screen import chest - await goKey(tester, keyRestoreChest); - - // Wait frame stop before continue - await tester.pumpAndSettle(); - - // Tap on button to paste mnemonic - await goKey(tester, keyPastMnemonic); - - // Tap on next button 4 times to skip 3 screen - await goKey(tester, keyGoNext); - await goKey(tester, keyGoNext); - await goKey(tester, keyGoNext); - await goKey(tester, keyGoNext); - - // Check if cached password checkbox is checked - final isCached = await isIconPresent(tester, Icons.check_box); - - // If not, tap on to cache password - if (!isCached) await goKey(tester, keyCachePassword, duration: 0); - - // Enter password - await enterText(tester, keyPinForm, 'AAAAA', 0); - - // Check if string "Accéder à mon coffre" is present in screen - await waitFor(tester, 'Accéder à mon coffre'); - - // Go to wallets home - await goKey(tester, keyGoWalletsHome, duration: 0); - - // Check if string "ĞD" is present in screen - await waitFor(tester, 'ĞD'); - - // Tap on add a new derivation button - await addDerivation(tester); - - // Tap on Wallet 5 - await goKey(tester, - keyOpenWallet('5Dq3giahrBfykJogPetZJ2jjSmhw49Fa7i6qKkseUvRJ2T3R')); - - // Copy address of Wallet 5 - await goKey(tester, keyCopyAddress); - - // Check if string "Cette adresse a été copié" is present in screen - await waitFor(tester, 'Cette adresse a été copié'); - - // Pop screen 2 time to go back home screen - await goBack(tester); - await goBack(tester); - - // Check if string "y'a pas de lézard" is present in screen - await waitFor(tester, "y'a pas de lézard"); -} - Future payTest2(WidgetTester tester) async { await waitFor(tester, 'Rechercher'); await goKey(tester, keyOpenSearch); final addressToSearch = (await Clipboard.getData('text/plain'))!.text; final endAddress = addressToSearch!.substring(addressToSearch.length - 6); - expect(addressToSearch, '5Dq3giahrBfykJogPetZJ2jjSmhw49Fa7i6qKkseUvRJ2T3R'); + expect(addressToSearch, test5.address); await enterText(tester, keySearchField, addressToSearch); await goKey(tester, keyConfirmSearch); await waitFor(tester, endAddress); @@ -132,46 +45,39 @@ Future payTest2(WidgetTester tester) async { await goKey(tester, keyPay); await enterText(tester, keyAmountField, '12.14'); await goKey(tester, keyConfirmPayment); - await spawnBlock(tester, keyCloseTransactionScreen); + await spawnBlock(tester); await waitFor(tester, 'validé !', timeout: const Duration(seconds: 1)); await goKey(tester, keyCloseTransactionScreen, duration: 0); await waitFor(tester, '12.14'); - await spawnBlock(tester, keyViewActivity); + await spawnBlock(tester); await waitFor(tester, '9.14'); } -Future addDerivation(WidgetTester tester) async { - await goKey(tester, keyAddDerivation); - await waitFor(tester, 'Portefeuille 5'); -} - Future certifyTest5(WidgetTester tester) async { // Create identity with Test1 account await goKey(tester, keyCertify); await goKey(tester, keyConfirm); - await spawnBlock(tester, keyViewActivity, duration: 500); + await spawnBlock(tester, duration: 500); await waitFor(tester, 'validé !', timeout: const Duration(seconds: 1)); await goKey(tester, keyCloseTransactionScreen); await waitFor(tester, 'Identité créée'); // Confirm Identity Test5 await goKey(tester, keyAppBarChest, duration: 300); - await goKey(tester, - keyOpenWallet('5Dq3giahrBfykJogPetZJ2jjSmhw49Fa7i6qKkseUvRJ2T3R')); + await goKey(tester, keyOpenWallet(test5.address)); await goKey(tester, keyCopyAddress); await goKey(tester, keyConfirmIdentity); - await enterText(tester, keyEnterIdentityUsername, 'test5'); + await enterText(tester, keyEnterIdentityUsername, test5.name); await goKey(tester, keyConfirm); - await spawnBlock(tester, keyCloseTransactionScreen, duration: 500); + await spawnBlock(tester, duration: 500); await waitFor(tester, 'validé !', timeout: const Duration(seconds: 1)); await goKey(tester, keyCloseTransactionScreen); await waitFor(tester, 'Identité confirmée'); // Set wallet 2 as default wallet await goBack(tester); - await goKey(tester, - keyOpenWallet('5E4i8vcNjnrDp21Sbnp32WHm2gz8YP3GGFwmdpfg5bHd8Whb')); + await goKey(tester, keyOpenWallet(test2.address)); await goKey(tester, keySetDefaultWallet); await waitFor(tester, 'Ce portefeuille est celui par defaut'); @@ -179,7 +85,7 @@ Future certifyTest5(WidgetTester tester) async { await goKey(tester, keyAppBarSearch); final addressToSearch = (await Clipboard.getData('text/plain'))!.text; final endAddress = addressToSearch!.substring(addressToSearch.length - 6); - expect(addressToSearch, '5Dq3giahrBfykJogPetZJ2jjSmhw49Fa7i6qKkseUvRJ2T3R'); + expect(addressToSearch, test5.address); await enterText(tester, keySearchField, addressToSearch); await goKey(tester, keyConfirmSearch); await waitFor(tester, endAddress); @@ -190,7 +96,7 @@ Future certifyTest5(WidgetTester tester) async { // Certify with test2 account await goKey(tester, keyCertify); await goKey(tester, keyConfirm); - await spawnBlock(tester, keyViewActivity, duration: 500); + await spawnBlock(tester, duration: 500); await waitFor(tester, 'validé !', timeout: const Duration(seconds: 1)); await goKey(tester, keyCloseTransactionScreen); await waitFor(tester, '2'); @@ -198,22 +104,20 @@ Future certifyTest5(WidgetTester tester) async { // Change default wallet to test3 await goKey(tester, keyPay); await goKey(tester, keyChangeChest); - await goKey(tester, - keySelectThisWallet('5FhTLzXLNBPmtXtDBFECmD7fvKmTtTQDtvBTfVr97tachA1p')); + await goKey(tester, keySelectThisWallet(test3.address)); await goKey(tester, keyConfirm); await sleep(tester); // Certify with test3 account await goKey(tester, keyCertify); await goKey(tester, keyConfirm); - await spawnBlock(tester, keyViewActivity, duration: 500); + await spawnBlock(tester, duration: 500); await waitFor(tester, 'validé !', timeout: const Duration(seconds: 1)); await goKey(tester, keyCloseTransactionScreen); await waitFor(tester, 'Vous devez attendre'); // Check if test5 is member await goKey(tester, keyAppBarChest, duration: 300); - await goKey(tester, - keyOpenWallet('5Dq3giahrBfykJogPetZJ2jjSmhw49Fa7i6qKkseUvRJ2T3R')); + await goKey(tester, keyOpenWallet(test5.address)); await waitFor(tester, 'Membre validé !'); } diff --git a/integration_test/general_actions.dart b/integration_test/general_actions.dart new file mode 100644 index 0000000..4ad5057 --- /dev/null +++ b/integration_test/general_actions.dart @@ -0,0 +1,96 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:gecko/globals.dart'; +import 'package:gecko/models/widgets_keys.dart'; +import 'tests_utility.dart'; + +// GENERAL ACTIONS + +Future changeNode(WidgetTester tester) async { + final ipAddress = dotenv.env['ip_address'] ?? '127.0.0.1'; + log.d('ip address: $ipAddress'); + + await goKey(tester, keyDrawerMenu); + await goKey(tester, keyParameters); + await goKey(tester, keySelectDuniterNodeDropDown, duration: 5); + await goKey(tester, keySelectDuniterNode('Personnalisé'), selectLast: true); + await enterText(tester, keyCustomDuniterEndpoint, 'ws://$ipAddress:9944'); + await goKey(tester, keyConnectToEndpoint); + await isIconPresent(tester, Icons.add_card_sharp, + timeout: const Duration(seconds: 8)); + await goBack(tester); +} + +Future deleteAllWallets(WidgetTester tester) async { + if (await isPresent(tester, 'Rechercher')) { + await goKey(tester, keyDrawerMenu); + await goKey(tester, keyParameters); + await goKey(tester, keyDeleteAllWallets); + await goKey(tester, keyConfirm); + await tester.pumpAndSettle(); + } +} + +Future restoreChest(WidgetTester tester) async { + // Copy test mnemonic in clipboard + Clipboard.setData(const ClipboardData(text: testMnemonic)); + + // Open screen import chest + await goKey(tester, keyRestoreChest); + + // Wait frame stop before continue + await tester.pumpAndSettle(); + + // Tap on button to paste mnemonic + await goKey(tester, keyPastMnemonic); + + // Tap on next button 4 times to skip 3 screen + await goKey(tester, keyGoNext); + await goKey(tester, keyGoNext); + await goKey(tester, keyGoNext); + await goKey(tester, keyGoNext); + + // Check if cached password checkbox is checked + final isCached = await isIconPresent(tester, Icons.check_box); + + // If not, tap on to cache password + if (!isCached) await goKey(tester, keyCachePassword, duration: 0); + + // Enter password + await enterText(tester, keyPinForm, 'AAAAA', 0); + + // Check if string "Accéder à mon coffre" is present in screen + await waitFor(tester, 'Accéder à mon coffre'); + + // Go to wallets home + await goKey(tester, keyGoWalletsHome, duration: 0); + + // Check if string "ĞD" is present in screen + await waitFor(tester, 'ĞD'); + + // Tap on add a new derivation button + await addDerivation(tester); + + // Tap on Wallet 5 + await goKey(tester, keyOpenWallet(test5.address)); + + // Copy address of Wallet 5 + await goKey(tester, keyCopyAddress); + + // Check if string "Cette adresse a été copié" is present in screen + await waitFor(tester, 'Cette adresse a été copié'); + + // Pop screen 2 time to go back home screen + await goBack(tester); + await goBack(tester); + + // Check if string "y'a pas de lézard" is present in screen + await waitFor(tester, "y'a pas de lézard"); +} + +Future addDerivation(WidgetTester tester) async { + await goKey(tester, keyAddDerivation); + await waitFor(tester, 'Portefeuille 5'); +} diff --git a/integration_test/tests_utility.dart b/integration_test/tests_utility.dart index 260f391..39785c3 100644 --- a/integration_test/tests_utility.dart +++ b/integration_test/tests_utility.dart @@ -4,6 +4,28 @@ import 'package:gecko/globals.dart'; import 'package:gecko/providers/substrate_sdk.dart'; import 'package:provider/provider.dart'; +final sub = Provider.of(homeContext, listen: false); + +// TEST WALLETS CONSTS +const testMnemonic = + 'pipe paddle ketchup filter life ice feel embody glide quantum ride usage'; +final test1 = + TestWallet('5FeggKqw2AbnGZF9Y9WPM2QTgzENS3Hit94Ewgmzdg5a3LNa', 'test1'); +final test2 = + TestWallet('5E4i8vcNjnrDp21Sbnp32WHm2gz8YP3GGFwmdpfg5bHd8Whb', 'test2'); +final test3 = + TestWallet('5FhTLzXLNBPmtXtDBFECmD7fvKmTtTQDtvBTfVr97tachA1p', 'test3'); +final test4 = + TestWallet('5DXJ4CusmCg8S1yF6JGVn4fxgk5oFx42WctXqHZ17mykgje5', 'test4'); +final test5 = + TestWallet('5Dq3giahrBfykJogPetZJ2jjSmhw49Fa7i6qKkseUvRJ2T3R', 'test5'); +// final test6 = +// TestWallet('5FeggKqw2AbnGZF9Y9WPM2QTgzENS3Hit94Ewgmzdg5a3LNa', 'test6'); +// final test7 = +// TestWallet('5FeggKqw2AbnGZF9Y9WPM2QTgzENS3Hit94Ewgmzdg5a3LNa', 'test7'); +// final test8 = +// TestWallet('5FeggKqw2AbnGZF9Y9WPM2QTgzENS3Hit94Ewgmzdg5a3LNa', 'test8'); + // CUSTOM FUNCTIONS Future sleep(WidgetTester tester, [int time = 1000]) async { @@ -37,14 +59,13 @@ Future enterText(WidgetTester tester, Key fieldKey, String textIn, await tester.enterText(find.byKey(fieldKey), textIn); } -Future waitFor( - WidgetTester tester, - String text, { - Duration timeout = const Duration(seconds: 5), -}) async { +Future waitFor(WidgetTester tester, String text, + {Duration timeout = const Duration(seconds: 5), + bool reverse = false, + bool exactMatch = false}) async { final end = DateTime.now().add(timeout); - Finder finder = find.textContaining(text); + Finder finder = exactMatch ? find.text(text) : find.textContaining(text); log.d('INTEGRATION TEST: Wait for: $text'); do { @@ -54,7 +75,7 @@ Future waitFor( await tester.pumpAndSettle(); await Future.delayed(const Duration(milliseconds: 100)); - } while (finder.evaluate().isEmpty); + } while (reverse ? finder.evaluate().isNotEmpty : finder.evaluate().isEmpty); } // Test if text is visible on screen, return a boolean @@ -77,13 +98,48 @@ Future isIconPresent(WidgetTester tester, IconData icon, return finder.evaluate().isEmpty ? false : true; } -Future spawnBlock(WidgetTester tester, Key customKey, +Future spawnBlock(WidgetTester tester, {int number = 1, int duration = 200}) async { if (duration != 0) { await sleep(tester, duration); } - final BuildContext context = tester.element(find.byKey(customKey)); - SubstrateSdk sub = Provider.of(context, listen: false); sub.spawnBlock(number); await sleep(tester, 500); } + +Future pay(WidgetTester tester, + {required String fromAddress, + required String destAddress, + required double amount}) async { + sub.pay( + fromAddress: fromAddress, + destAddress: destAddress, + amount: amount, + password: 'AAAAA'); + spawnBlock(tester, duration: 500); + await sleep(tester, 500); +} + +Future certify(WidgetTester tester, + {required String fromAddress, required String destAddress}) async { + sub.certify(fromAddress, destAddress, 'AAAAA'); + spawnBlock(tester, duration: 500); + await sleep(tester, 500); +} + +Future confirmIdentity(WidgetTester tester, + {required String fromAddress, required String name}) async { + sub.confirmIdentity(fromAddress, name, 'AAAAA'); + spawnBlock(tester, duration: 500); + await sleep(tester, 500); +} + +class TestWallet { + String address; + String name; + + TestWallet(this.address, this.name); + + endAddress() => address.substring(address.length - 6); + shortAddress() => getShortPubkey(address); +} diff --git a/lib/providers/substrate_sdk.dart b/lib/providers/substrate_sdk.dart index 9f7e225..ccd81b1 100644 --- a/lib/providers/substrate_sdk.dart +++ b/lib/providers/substrate_sdk.dart @@ -696,14 +696,14 @@ class SubstrateSdk with ChangeNotifier { } Future certify( - String fromAddress, String password, String toAddress) async { + String fromAddress, String destAddress, String password) async { transactionStatus = ''; final myIdtyStatus = await idtyStatus(fromAddress); - final toIdtyStatus = await idtyStatus(toAddress); + final toIdtyStatus = await idtyStatus(destAddress); final fromIndex = await _getIdentityIndexOf(fromAddress); - final toIndex = await _getIdentityIndexOf(toAddress); + final toIndex = await _getIdentityIndexOf(destAddress); if (myIdtyStatus != 'Validated') { transactionStatus = 'notMember'; @@ -716,7 +716,7 @@ class SubstrateSdk with ChangeNotifier { List txOptions = []; String? rawParams; - final toCerts = await getCerts(toAddress); + final toCerts = await getCerts(destAddress); // log.d('debug: ${currencyParameters['minCertForMembership']}'); @@ -726,7 +726,7 @@ class SubstrateSdk with ChangeNotifier { 'createIdentity', sender, ); - txOptions = [toAddress]; + txOptions = [destAddress]; } else if (toIdtyStatus == 'Validated' || toIdtyStatus == 'ConfirmedByOwner') { if (toCerts[0] >= currencyParameters['minCertForMembership']! - 1 && @@ -776,11 +776,11 @@ class SubstrateSdk with ChangeNotifier { Future confirmIdentity( String fromAddress, String name, String password) async { - log.d('me: ${keyring.current.address!}'); + final fromPubkey = await sdk.api.account.decodeAddress([fromAddress]); final sender = TxSenderData( - keyring.current.address, - keyring.current.pubKey, + fromAddress, + fromPubkey!.keys.first, ); final txInfo = TxInfoData( diff --git a/lib/screens/wallet_view.dart b/lib/screens/wallet_view.dart index 29b6db6..d02757b 100644 --- a/lib/screens/wallet_view.dart +++ b/lib/screens/wallet_view.dart @@ -246,8 +246,9 @@ class WalletViewScreen extends StatelessWidget { final acc = sub.getCurrentWallet(); sub.certify( acc.address!, - pin ?? myWalletProvider.pinCode, - walletViewProvider.address!); + walletViewProvider.address!, + pin ?? + myWalletProvider.pinCode); Navigator.push( context,