From 3d328ecfc4c88e27b33fef9046b73363df2d997b Mon Sep 17 00:00:00 2001 From: poka Date: Sun, 18 Apr 2021 23:45:02 +0200 Subject: [PATCH 01/14] First integration test is OK ! (feat @elois) --- lib/screens/commonElements.dart | 3 +- lib/screens/home.dart | 1 + lib/screens/onBoarding/0_noKeychainFound.dart | 4 +- pubspec.lock | 202 +++++++++++++++++- pubspec.yaml | 5 +- test_driver/app.dart | 11 + test_driver/app_test.dart | 50 +++++ 7 files changed, 267 insertions(+), 9 deletions(-) create mode 100644 test_driver/app.dart create mode 100644 test_driver/app_test.dart diff --git a/lib/screens/commonElements.dart b/lib/screens/commonElements.dart index 59bc2b6..80d4f78 100644 --- a/lib/screens/commonElements.dart +++ b/lib/screens/commonElements.dart @@ -7,7 +7,7 @@ class CommonElements { return Text('Coucou'); } - Widget bubbleSpeak(String text, {double long}) { + Widget bubbleSpeak(String text, {double long, Key textKey}) { return Bubble( padding: long == null ? BubbleEdges.all(18) @@ -18,6 +18,7 @@ class CommonElements { // nip: BubbleNip.leftTop, child: Text( text, + key: textKey, style: TextStyle( color: Colors.black, fontSize: 18, fontWeight: FontWeight.w400), ), diff --git a/lib/screens/home.dart b/lib/screens/home.dart index b21bc7d..e8951dc 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -257,6 +257,7 @@ class HomeScreen extends StatelessWidget { Column(children: [ Container( child: ClipOval( + key: Key('manageWallets'), child: Material( color: Color(0xffFFD58D), // button color child: InkWell( diff --git a/lib/screens/onBoarding/0_noKeychainFound.dart b/lib/screens/onBoarding/0_noKeychainFound.dart index d5c9acb..f4ed053 100644 --- a/lib/screens/onBoarding/0_noKeychainFound.dart +++ b/lib/screens/onBoarding/0_noKeychainFound.dart @@ -23,8 +23,8 @@ class NoKeyChainScreen extends StatelessWidget { child: Column(children: [ common.onboardingProgressBar(context, 'Mes portefeuilles', 0), common.bubbleSpeak( - "Je ne connais pour l’instant aucun de vos portefeuilles.\n\nVous pouvez en créer un nouveau, ou bien importer un portefeuille Cesium existant.", - ), + "Je ne connais pour l’instant aucun de vos portefeuilles.\n\nVous pouvez en créer un nouveau, ou bien importer un portefeuille Cesium existant.", + textKey: Key('textOnboarding')), SizedBox(height: 90), Container( child: ClipOval( diff --git a/pubspec.lock b/pubspec.lock index 6d1b885..8c8924d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,20 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + url: "https://pub.dartlang.org" + source: hosted + version: "20.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + url: "https://pub.dartlang.org" + source: hosted + version: "1.4.0" archive: dependency: transitive description: @@ -64,6 +78,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" + cli_util: + dependency: transitive + description: + name: cli_util + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.0" clock: dependency: transitive description: @@ -99,13 +120,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.1" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + coverage: + dependency: transitive + description: + name: coverage + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" crypto: dependency: "direct main" description: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.1" dubp: dependency: "direct main" description: @@ -153,6 +188,11 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_driver: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" flutter_launcher_icons: dependency: "direct main" description: @@ -191,6 +231,18 @@ packages: description: flutter source: sdk version: "0.0.0" + fuchsia_remote_debug_protocol: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + glob: + dependency: transitive + description: + name: glob + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" globbing: dependency: transitive description: @@ -275,6 +327,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.13.0" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" http_parser: dependency: transitive description: @@ -324,6 +383,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.17.0" + io: + dependency: transitive + description: + name: io + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" isolate: dependency: transitive description: @@ -352,6 +418,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.0" + logging: + dependency: transitive + description: + name: logging + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" matcher: dependency: transitive description: @@ -366,6 +439,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0" + mime: + dependency: transitive + description: + name: mime + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" nested: dependency: transitive description: @@ -373,6 +453,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.0.4" + node_preamble: + dependency: transitive + description: + name: node_preamble + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" normalize: dependency: transitive description: @@ -380,6 +467,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.5.0-nullsafety.0" + package_config: + dependency: transitive + description: + name: package_config + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" package_info: dependency: "direct main" description: @@ -541,6 +635,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.0" + pool: + dependency: transitive + description: + name: pool + url: "https://pub.dartlang.org" + source: hosted + version: "1.5.0" printing: dependency: "direct main" description: @@ -554,7 +655,7 @@ packages: name: process url: "https://pub.dartlang.org" source: hosted - version: "4.1.0" + version: "4.2.1" provider: dependency: "direct main" description: @@ -562,6 +663,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.3.2+3" + pub_semver: + dependency: transitive + description: + name: pub_semver + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" qr: dependency: transitive description: @@ -653,18 +761,60 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.0" + shelf: + dependency: transitive + description: + name: shelf + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + shelf_static: + dependency: transitive + description: + name: shelf_static + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + source_maps: + dependency: transitive + description: + name: source_maps + url: "https://pub.dartlang.org" + source: hosted + version: "0.10.10" source_span: dependency: transitive description: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.0" + version: "1.8.1" stack_trace: dependency: transitive description: @@ -699,7 +849,7 @@ packages: name: sync_http url: "https://pub.dartlang.org" source: hosted - version: "0.2.0" + version: "0.3.0" system_info: dependency: transitive description: @@ -714,13 +864,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" + test: + dependency: "direct main" + description: + name: test + url: "https://pub.dartlang.org" + source: hosted + version: "1.16.8" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.19" + version: "0.3.0" + test_core: + dependency: transitive + description: + name: test_core + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.19" truncate: dependency: "direct main" description: @@ -749,6 +913,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + vm_service: + dependency: transitive + description: + name: vm_service + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.0+1" + watcher: + dependency: transitive + description: + name: watcher + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" web_socket_channel: dependency: transitive description: @@ -756,6 +934,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.0" + webdriver: + dependency: transitive + description: + name: webdriver + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" win32: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 89976f8..5c6eeb0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -34,7 +34,7 @@ dependencies: pdf: ^3.0.1 printing: ^5.0.2 shared_preferences: ^2.0.3 - sync_http: ^0.2.0 + sync_http: ^0.3.0 crypto: ^3.0.0 fast_base58: logger: ^1.0.0 @@ -47,6 +47,9 @@ dependencies: responsive_builder: ^0.3.0 jdenticon_dart: ^2.0.0 audioplayers: ^0.18.1 + flutter_driver: + sdk: flutter + test: ^1.16.6 flutter_icons: android: "ic_launcher" diff --git a/test_driver/app.dart b/test_driver/app.dart new file mode 100644 index 0000000..ec9a318 --- /dev/null +++ b/test_driver/app.dart @@ -0,0 +1,11 @@ +import 'package:flutter_driver/driver_extension.dart'; +import 'package:gecko/main.dart' as app; + +void main() { + // This line enables the extension. + enableFlutterDriverExtension(); + + // Call the `main()` function of the app, or call `runApp` with + // any widget you are interested in testing. + app.main(); +} diff --git a/test_driver/app_test.dart b/test_driver/app_test.dart new file mode 100644 index 0000000..f87cbf9 --- /dev/null +++ b/test_driver/app_test.dart @@ -0,0 +1,50 @@ +// Imports the Flutter Driver API. +import 'package:flutter_driver/flutter_driver.dart'; +// import 'package:flutter_test/flutter_test.dart'; +import 'package:test/test.dart'; + +void main() { + group('Counter App', () { + // First, define the Finders and use them to locate widgets from the + // test suite. Note: the Strings provided to the `byValueKey` method must + // be the same as the Strings we used for the Keys in step 1. + final manageWalletsFinder = find.byValueKey('manageWallets'); + // final buttonFinder = find.byValueKey('increment'); + + FlutterDriver driver; + + // Connect to the Flutter driver before running any tests. + setUpAll(() async { + driver = await FlutterDriver.connect(); + await driver.waitUntilFirstFrameRasterized(); + }); + + // Close the connection to the driver after the tests have completed. + tearDownAll(() async { + if (driver != null) { + driver.close(); + } + }); + + test('Open wallets management', () async { + await driver.runUnsynchronized(() async { + // First, tap the button. + await driver.tap(manageWalletsFinder); + + // tester.tap(find.widgetWithText(Button, 'Update')); + // + + SerializableFinder textOnboarding = find.byValueKey( + 'textOnboarding', + ); + + print( + '####################################################################'); + + // Then, verify the counter text is incremented by 1. + expect(await driver.getText(textOnboarding), + "Je ne connais pour l’instant aucun de vos portefeuilles.\n\nVous pouvez en créer un nouveau, ou bien importer un portefeuille Cesium existant."); + }); + }); + }); +} From a85229048c8f940a4de2345d8ffe5eed330dd787 Mon Sep 17 00:00:00 2001 From: poka Date: Mon, 19 Apr 2021 14:17:42 +0200 Subject: [PATCH 02/14] Prepare to get integration test to the moon --- test_driver/app_test.dart | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/test_driver/app_test.dart b/test_driver/app_test.dart index f87cbf9..aeebab8 100644 --- a/test_driver/app_test.dart +++ b/test_driver/app_test.dart @@ -4,7 +4,7 @@ import 'package:flutter_driver/flutter_driver.dart'; import 'package:test/test.dart'; void main() { - group('Counter App', () { + group('Gecko App', () { // First, define the Finders and use them to locate widgets from the // test suite. Note: the Strings provided to the `byValueKey` method must // be the same as the Strings we used for the Keys in step 1. @@ -26,14 +26,12 @@ void main() { } }); - test('Open wallets management', () async { + test('Open wallets management - OnBoarding', () async { await driver.runUnsynchronized(() async { - // First, tap the button. + // First, tap the button manage wallets await driver.tap(manageWalletsFinder); - // tester.tap(find.widgetWithText(Button, 'Update')); - // - + // Get the SerializableFinder for text widget with key 'textOnboarding' SerializableFinder textOnboarding = find.byValueKey( 'textOnboarding', ); @@ -41,7 +39,7 @@ void main() { print( '####################################################################'); - // Then, verify the counter text is incremented by 1. + // Verify onboarding is starting, with text expect(await driver.getText(textOnboarding), "Je ne connais pour l’instant aucun de vos portefeuilles.\n\nVous pouvez en créer un nouveau, ou bien importer un portefeuille Cesium existant."); }); From e8aaa0e2c02952a46a2bded11fcb582b938d3b4c Mon Sep 17 00:00:00 2001 From: poka Date: Sat, 24 Apr 2021 20:27:18 +0200 Subject: [PATCH 03/14] Test go to restore sentance generation --- lib/screens/commonElements.dart | 15 +++---- lib/screens/onBoarding/0_noKeychainFound.dart | 1 + lib/screens/onBoarding/1.dart | 5 ++- lib/screens/onBoarding/10.dart | 5 ++- lib/screens/onBoarding/11.dart | 26 +++++++----- lib/screens/onBoarding/12.dart | 4 +- .../onBoarding/13_congratulations.dart | 2 + lib/screens/onBoarding/2.dart | 2 + lib/screens/onBoarding/3.dart | 2 + lib/screens/onBoarding/4.dart | 2 + lib/screens/onBoarding/5.dart | 2 + lib/screens/onBoarding/6.dart | 2 + lib/screens/onBoarding/7.dart | 2 + lib/screens/onBoarding/8.dart | 30 +++++++------ lib/screens/onBoarding/9.dart | 22 ++++++---- test_driver/app_test.dart | 42 ++++++++++++------- 16 files changed, 106 insertions(+), 58 deletions(-) diff --git a/lib/screens/commonElements.dart b/lib/screens/commonElements.dart index 80d4f78..b6c3d6b 100644 --- a/lib/screens/commonElements.dart +++ b/lib/screens/commonElements.dart @@ -25,7 +25,7 @@ class CommonElements { ); } - Widget bubbleSpeakRich(List text) { + Widget bubbleSpeakRich(List text, {Key textKey}) { return Bubble( padding: BubbleEdges.all(18), elevation: 5, @@ -33,13 +33,14 @@ class CommonElements { margin: BubbleEdges.fromLTRB(10, 0, 20, 10), // nip: BubbleNip.leftTop, child: RichText( + key: textKey, text: TextSpan( - style: TextStyle( - fontSize: 18.0, - color: Colors.black, - ), - children: text, - )), + style: TextStyle( + fontSize: 18.0, + color: Colors.black, + ), + children: text, + )), ); } diff --git a/lib/screens/onBoarding/0_noKeychainFound.dart b/lib/screens/onBoarding/0_noKeychainFound.dart index f4ed053..3cc2c10 100644 --- a/lib/screens/onBoarding/0_noKeychainFound.dart +++ b/lib/screens/onBoarding/0_noKeychainFound.dart @@ -31,6 +31,7 @@ class NoKeyChainScreen extends StatelessWidget { child: Material( color: Color(0xffFFD58D), // button color child: InkWell( + key: Key('goStep1'), splashColor: Color(0xffD28928), // inkwell color child: Padding( padding: EdgeInsets.all(8), diff --git a/lib/screens/onBoarding/1.dart b/lib/screens/onBoarding/1.dart index 8be6764..cf6ba13 100644 --- a/lib/screens/onBoarding/1.dart +++ b/lib/screens/onBoarding/1.dart @@ -22,8 +22,8 @@ class OnboardingStepOne extends StatelessWidget { common.onboardingProgressBar( context, 'Nouveau portefeuilles', progress), common.bubbleSpeak( - "Il semblerait que vous n’ayez pas encore de trousseau.\n\nUn trousseau vous permet de gérer un ou plusieurs portefeuilles.", - ), + "Il semblerait que vous n’ayez pas encore de trousseau.\n\nUn trousseau vous permet de gérer un ou plusieurs portefeuilles.", + textKey: Key('step1')), SizedBox(height: 90), Image.asset( 'assets/onBoarding/keys-and-wallets-horizontal.png', @@ -36,6 +36,7 @@ class OnboardingStepOne extends StatelessWidget { width: 400, height: 62, child: ElevatedButton( + key: Key('goStep2'), style: ElevatedButton.styleFrom( elevation: 5, primary: Color(0xffD28928), diff --git a/lib/screens/onBoarding/10.dart b/lib/screens/onBoarding/10.dart index a70f5e8..798d463 100644 --- a/lib/screens/onBoarding/10.dart +++ b/lib/screens/onBoarding/10.dart @@ -21,7 +21,9 @@ class OnboardingStepTwelve extends StatelessWidget { common.onboardingProgressBar( context, 'Ma phrase de restauration', progress), common.bubbleSpeak( - "Si un jour vous changez de téléphone, votre code secret sera différent, mais il vous suffira de me redonner votre phrase de restauration pour recréer votre trousseau."), + "Si un jour vous changez de téléphone, votre code secret sera différent, mais il vous suffira de me redonner votre phrase de restauration pour recréer votre trousseau.", + textKey: Key('step10'), + ), SizedBox(height: 10), Image.asset( 'assets/onBoarding/plusieurs-codes-secrets-un-trousseau.png', @@ -34,6 +36,7 @@ class OnboardingStepTwelve extends StatelessWidget { width: 400, height: 62, child: ElevatedButton( + key: Key('goStep11'), style: ElevatedButton.styleFrom( elevation: 5, primary: Color(0xffD28928), diff --git a/lib/screens/onBoarding/11.dart b/lib/screens/onBoarding/11.dart index b10fd02..f622416 100644 --- a/lib/screens/onBoarding/11.dart +++ b/lib/screens/onBoarding/11.dart @@ -35,17 +35,20 @@ class OnboardingStepThirteen extends StatelessWidget { }), common.onboardingProgressBar( context, 'Ma phrase de restauration', progress), - common.bubbleSpeakRich([ - TextSpan( - text: - "Et voilà votre code secret !\n\nMémorisez-le ou notez-le, car il vous sera demandé "), - TextSpan( - text: 'à chaque fois', - style: TextStyle(fontWeight: FontWeight.bold)), - TextSpan( - text: - " que vous voudrez effectuer un paiement sur cet appareil."), - ]), + common.bubbleSpeakRich( + [ + TextSpan( + text: + "Et voilà votre code secret !\n\nMémorisez-le ou notez-le, car il vous sera demandé "), + TextSpan( + text: 'à chaque fois', + style: TextStyle(fontWeight: FontWeight.bold)), + TextSpan( + text: + " que vous voudrez effectuer un paiement sur cet appareil."), + ], + textKey: Key('step11'), + ), SizedBox(height: 100), Container( child: Stack( @@ -97,6 +100,7 @@ class OnboardingStepThirteen extends StatelessWidget { width: 400, height: 62, child: ElevatedButton( + key: Key('goStep12'), style: ElevatedButton.styleFrom( elevation: 5, primary: Color(0xffD28928), diff --git a/lib/screens/onBoarding/12.dart b/lib/screens/onBoarding/12.dart index 7d10415..48326c1 100644 --- a/lib/screens/onBoarding/12.dart +++ b/lib/screens/onBoarding/12.dart @@ -42,7 +42,9 @@ class OnboardingStepFourteen extends StatelessWidget { common.onboardingProgressBar( context, 'Ma phrase de restauration', progress), common.bubbleSpeak( - "Avez-vous bien mémorisé votre code secret ?\n\nVérifions ça ensemble !\n\nTapez votre code secret dans le champ ci-dessous (après c’est fini, promis-juré-gecko)."), + "Avez-vous bien mémorisé votre code secret ?\n\nVérifions ça ensemble !\n\nTapez votre code secret dans le champ ci-dessous (après c’est fini, promis-juré-gecko).", + textKey: Key('step12'), + ), SizedBox(height: isTall ? 80 : 10), pinForm(context, _walletOptions, _pinLenght, 1, 3) ]), diff --git a/lib/screens/onBoarding/13_congratulations.dart b/lib/screens/onBoarding/13_congratulations.dart index 2cde659..0a1f432 100644 --- a/lib/screens/onBoarding/13_congratulations.dart +++ b/lib/screens/onBoarding/13_congratulations.dart @@ -21,6 +21,7 @@ class OnboardingStepFiveteen extends StatelessWidget { context, 'Ma phrase de restauration', progress), common.bubbleSpeak( "Top !\n\nVotre trousseau de clef et votre portefeuille ont été créés avec un immense succès.\n\nFélicitations !", + textKey: Key('step13'), ), SizedBox(height: isTall ? 20 : 10), Image.asset( @@ -34,6 +35,7 @@ class OnboardingStepFiveteen extends StatelessWidget { width: 400, height: 62, child: ElevatedButton( + key: Key('goWalletHome'), style: ElevatedButton.styleFrom( elevation: 5, primary: Color(0xffD28928), diff --git a/lib/screens/onBoarding/2.dart b/lib/screens/onBoarding/2.dart index 6cdfaf8..0c22019 100644 --- a/lib/screens/onBoarding/2.dart +++ b/lib/screens/onBoarding/2.dart @@ -24,6 +24,7 @@ class OnboardingStepTwo extends StatelessWidget { context, 'Nouveau portefeuilles', progress), common.bubbleSpeak( "Un trousseau est créé à partir d’une phrase de restauration.", + textKey: Key('step2'), ), SizedBox(height: 70), Image.asset( @@ -35,6 +36,7 @@ class OnboardingStepTwo extends StatelessWidget { width: 400, height: 62, child: ElevatedButton( + key: Key('goStep3'), style: ElevatedButton.styleFrom( elevation: 5, primary: Color(0xffD28928), diff --git a/lib/screens/onBoarding/3.dart b/lib/screens/onBoarding/3.dart index 279568f..2300cbb 100644 --- a/lib/screens/onBoarding/3.dart +++ b/lib/screens/onBoarding/3.dart @@ -22,6 +22,7 @@ class OnboardingStepFor extends StatelessWidget { context, 'Ma phrase de restauration', progress), common.bubbleSpeak( "Si un jour vous changez de téléphone, il vous suffira de me redonner votre phrase de restauration pour recréer votre trousseau.", + textKey: Key('step3'), ), SizedBox(height: isTall ? 15 : 0), // Row(children: [ @@ -40,6 +41,7 @@ class OnboardingStepFor extends StatelessWidget { width: 400, height: 62, child: ElevatedButton( + key: Key('goStep4'), style: ElevatedButton.styleFrom( elevation: 5, primary: Color(0xffD28928), diff --git a/lib/screens/onBoarding/4.dart b/lib/screens/onBoarding/4.dart index 4f239df..bb08542 100644 --- a/lib/screens/onBoarding/4.dart +++ b/lib/screens/onBoarding/4.dart @@ -22,6 +22,7 @@ class OnboardingStepFive extends StatelessWidget { context, 'Ma phrase de restauration', progress), common.bubbleSpeak( "Par contre, attention :\n\nDans une blockchain, il n’y a pas de procédure de récupération de trousseau.\n\nSi vous perdez votre phrase de restauration, je ne pourrai pas vous la communiquer, et vous ne pourrez donc plus jamais accéder à votre compte.", + textKey: Key('step4'), ), SizedBox(height: isTall ? 30 : 10), Image.asset( @@ -35,6 +36,7 @@ class OnboardingStepFive extends StatelessWidget { width: 400, height: 62, child: ElevatedButton( + key: Key('goStep5'), style: ElevatedButton.styleFrom( elevation: 5, primary: Color(0xffD28928), diff --git a/lib/screens/onBoarding/5.dart b/lib/screens/onBoarding/5.dart index 38eeece..c2135ba 100644 --- a/lib/screens/onBoarding/5.dart +++ b/lib/screens/onBoarding/5.dart @@ -30,6 +30,7 @@ class OnboardingStepSeven extends StatelessWidget { text: "afin de pouvoir noter votre phrase de restauration."), ], + textKey: Key('step5'), ), Expanded( child: Align( @@ -52,6 +53,7 @@ class OnboardingStepSeven extends StatelessWidget { width: 400, height: 62, child: ElevatedButton( + key: Key('goStep6'), style: ElevatedButton.styleFrom( elevation: 5, primary: Color(0xffD28928), diff --git a/lib/screens/onBoarding/6.dart b/lib/screens/onBoarding/6.dart index 2988d1a..97eacfe 100644 --- a/lib/screens/onBoarding/6.dart +++ b/lib/screens/onBoarding/6.dart @@ -23,6 +23,7 @@ class OnboardingStepEight extends StatelessWidget { context, 'Ma phrase de restauration', progress), common.bubbleSpeak( "J’ai généré votre phrase de restauration !\nTâchez de la garder bien secrète, car elle permet à quiconque la connaît d’accéder à tous vos portefeuilles.", + textKey: Key('step6'), ), SizedBox(height: isTall ? 61 : 31), // SizedBox(height: 30), @@ -35,6 +36,7 @@ class OnboardingStepEight extends StatelessWidget { width: 400, height: 62, child: ElevatedButton( + key: Key('goStep7'), style: ElevatedButton.styleFrom( elevation: 5, primary: Color(0xffD28928), diff --git a/lib/screens/onBoarding/7.dart b/lib/screens/onBoarding/7.dart index be08955..f0f865c 100644 --- a/lib/screens/onBoarding/7.dart +++ b/lib/screens/onBoarding/7.dart @@ -29,6 +29,7 @@ class OnboardingStepNine extends StatelessWidget { context, 'Ma phrase de restauration', progress), common.bubbleSpeak( "C’est le moment de noter votre phrase !", + textKey: Key('step7'), long: 60, ), SizedBox(height: isTall ? 100 : 70), @@ -71,6 +72,7 @@ class OnboardingStepNine extends StatelessWidget { width: 400, height: 62, child: ElevatedButton( + key: Key('goStep8'), style: ElevatedButton.styleFrom( elevation: 5, primary: Color(0xffD28928), diff --git a/lib/screens/onBoarding/8.dart b/lib/screens/onBoarding/8.dart index 020e8c3..e740527 100644 --- a/lib/screens/onBoarding/8.dart +++ b/lib/screens/onBoarding/8.dart @@ -46,19 +46,22 @@ class OnboardingStepTen extends StatelessWidget { child: Column(children: [ common.onboardingProgressBar( context, 'Valider ma phrase de restauration', progress), - common.bubbleSpeakRich([ - TextSpan( - text: - "Avez-vous bien noté votre phrase de restauration ?\n\nPour en être sûr, veuillez taper dans le champ ci-dessous le ", - style: TextStyle(fontSize: 16 * ratio)), - TextSpan( - text: '${_generateWalletProvider.nbrWord + 1}ème mot', - style: TextStyle( - fontWeight: FontWeight.bold, fontSize: 16 * ratio)), - TextSpan( - text: " de votre phrase de restauration :", - style: TextStyle(fontSize: 16 * ratio)), - ]), + common.bubbleSpeakRich( + [ + TextSpan( + text: + "Avez-vous bien noté votre phrase de restauration ?\n\nPour en être sûr, veuillez taper dans le champ ci-dessous le ", + style: TextStyle(fontSize: 16 * ratio)), + TextSpan( + text: '${_generateWalletProvider.nbrWord + 1}ème mot', + style: TextStyle( + fontWeight: FontWeight.bold, fontSize: 16 * ratio)), + TextSpan( + text: " de votre phrase de restauration :", + style: TextStyle(fontSize: 16 * ratio)), + ], + textKey: Key('step8'), + ), // LayoutBuilder(builder: (builder, constraints) { // // 2 @@ -154,6 +157,7 @@ class OnboardingStepTen extends StatelessWidget { width: 400, height: 62, child: ElevatedButton( + key: Key('goStep9'), style: ElevatedButton.styleFrom( elevation: 5, primary: Color(0xffD28928), diff --git a/lib/screens/onBoarding/9.dart b/lib/screens/onBoarding/9.dart index d34f138..3c0a876 100644 --- a/lib/screens/onBoarding/9.dart +++ b/lib/screens/onBoarding/9.dart @@ -20,15 +20,18 @@ class OnboardingStepEleven extends StatelessWidget { child: Column(children: [ common.onboardingProgressBar( context, 'Ma phrase de restauration', progress), - common.bubbleSpeakRich([ - TextSpan(text: "Super !\n\nJe vais maintenant créer votre "), - TextSpan( - text: 'code secret.', - style: TextStyle(fontWeight: FontWeight.bold)), - TextSpan( - text: - " \n\nVotre code secret chiffre votre trousseau de clefs, ce qui le rend inutilisable par d’autres, par exemple si vous perdez votre téléphone ou si on vous le vole."), - ]), + common.bubbleSpeakRich( + [ + TextSpan(text: "Super !\n\nJe vais maintenant créer votre "), + TextSpan( + text: 'code secret.', + style: TextStyle(fontWeight: FontWeight.bold)), + TextSpan( + text: + " \n\nVotre code secret chiffre votre trousseau de clefs, ce qui le rend inutilisable par d’autres, par exemple si vous perdez votre téléphone ou si on vous le vole."), + ], + textKey: Key('step8'), + ), SizedBox(height: isTall ? 50 : 10), Image.asset( 'assets/onBoarding/treasure-chest-gecko-souligne.png', @@ -41,6 +44,7 @@ class OnboardingStepEleven extends StatelessWidget { width: 400, height: 62, child: ElevatedButton( + key: Key('goStep10'), style: ElevatedButton.styleFrom( elevation: 5, primary: Color(0xffD28928), diff --git a/test_driver/app_test.dart b/test_driver/app_test.dart index aeebab8..670f1fa 100644 --- a/test_driver/app_test.dart +++ b/test_driver/app_test.dart @@ -26,23 +26,37 @@ void main() { } }); - test('Open wallets management - OnBoarding', () async { - await driver.runUnsynchronized(() async { - // First, tap the button manage wallets - await driver.tap(manageWalletsFinder); + test('OnBoarding - Open wallets management', ( + {timeout: const Duration(seconds: 2)}) async { + // await driver.runUnsynchronized(() async { // Needed if we want to manage async drivers + await driver.tap(manageWalletsFinder); - // Get the SerializableFinder for text widget with key 'textOnboarding' - SerializableFinder textOnboarding = find.byValueKey( - 'textOnboarding', - ); + // Get the SerializableFinder for text widget with key 'textOnboarding' + SerializableFinder textOnboarding = find.byValueKey( + 'textOnboarding', + ); - print( - '####################################################################'); + print( + '####################################################################'); - // Verify onboarding is starting, with text - expect(await driver.getText(textOnboarding), - "Je ne connais pour l’instant aucun de vos portefeuilles.\n\nVous pouvez en créer un nouveau, ou bien importer un portefeuille Cesium existant."); - }); + // Verify onboarding is starting, with text + expect(await driver.getText(textOnboarding), + "Je ne connais pour l’instant aucun de vos portefeuilles.\n\nVous pouvez en créer un nouveau, ou bien importer un portefeuille Cesium existant."); + }); + + test('OnBoarding - Go to create restore sentance', ( + {timeout: const Duration(seconds: 5)}) async { + await driver.tap(find.byValueKey('goStep1')); + await driver.tap(find.byValueKey('goStep2')); + await driver.tap(find.byValueKey('goStep3')); + await driver.tap(find.byValueKey('goStep4')); + await driver.tap(find.byValueKey('goStep5')); + + expect( + await driver.getText(find.byValueKey( + 'step5', + )), + "Munissez-vous d'un papier et d’un crayon\nafin de pouvoir noter votre phrase de restauration."); }); }); } From 8b5752b1bfb27d024c90ced2c965550b660792d3 Mon Sep 17 00:00:00 2001 From: poka Date: Sat, 24 Apr 2021 21:53:28 +0200 Subject: [PATCH 04/14] Go to generation screen test; add script to start tests --- scripts/startIntegrationsTests.sh | 3 +++ test_driver/app_test.dart | 14 +++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100755 scripts/startIntegrationsTests.sh diff --git a/scripts/startIntegrationsTests.sh b/scripts/startIntegrationsTests.sh new file mode 100755 index 0000000..eca24d1 --- /dev/null +++ b/scripts/startIntegrationsTests.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +flutter drive --target=test_driver/app.dart diff --git a/test_driver/app_test.dart b/test_driver/app_test.dart index 670f1fa..0aaea5e 100644 --- a/test_driver/app_test.dart +++ b/test_driver/app_test.dart @@ -51,10 +51,22 @@ void main() { await driver.tap(find.byValueKey('goStep3')); await driver.tap(find.byValueKey('goStep4')); await driver.tap(find.byValueKey('goStep5')); + await driver.tap(find.byValueKey('goStep6')); expect( await driver.getText(find.byValueKey( - 'step5', + 'step6', + )), + "J’ai généré votre phrase de restauration !\nTâchez de la garder bien secrète, car elle permet à quiconque la connaît d’accéder à tous vos portefeuilles."); + }); + + test('OnBoarding - Generate sentance', ( + {timeout: const Duration(seconds: 5)}) async { + await driver.tap(find.byValueKey('goStep6')); + + expect( + await driver.getText(find.byValueKey( + 'step7', )), "Munissez-vous d'un papier et d’un crayon\nafin de pouvoir noter votre phrase de restauration."); }); From 7427e0a3303ad16a6e90aff3fb70ff65a084736d Mon Sep 17 00:00:00 2001 From: poka Date: Sat, 24 Apr 2021 21:58:18 +0200 Subject: [PATCH 05/14] fix last test --- lib/screens/onBoarding/7.dart | 2 +- test_driver/app_test.dart | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/screens/onBoarding/7.dart b/lib/screens/onBoarding/7.dart index f0f865c..3d685d1 100644 --- a/lib/screens/onBoarding/7.dart +++ b/lib/screens/onBoarding/7.dart @@ -28,7 +28,7 @@ class OnboardingStepNine extends StatelessWidget { common.onboardingProgressBar( context, 'Ma phrase de restauration', progress), common.bubbleSpeak( - "C’est le moment de noter votre phrase !", + "C'est le moment de noter votre phrase !", textKey: Key('step7'), long: 60, ), diff --git a/test_driver/app_test.dart b/test_driver/app_test.dart index 0aaea5e..a1c30e8 100644 --- a/test_driver/app_test.dart +++ b/test_driver/app_test.dart @@ -62,13 +62,13 @@ void main() { test('OnBoarding - Generate sentance', ( {timeout: const Duration(seconds: 5)}) async { - await driver.tap(find.byValueKey('goStep6')); + await driver.tap(find.byValueKey('goStep7')); expect( await driver.getText(find.byValueKey( 'step7', )), - "Munissez-vous d'un papier et d’un crayon\nafin de pouvoir noter votre phrase de restauration."); + "C'est le moment de noter votre phrase !"); }); }); } From a906dc2f3878bf5e91a5da73d3ffc3976ebc2d5c Mon Sep 17 00:00:00 2001 From: poka Date: Mon, 26 Apr 2021 19:23:00 +0200 Subject: [PATCH 06/14] Get mnemonic from DEWIF (commented) --- lib/models/walletOptions.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/models/walletOptions.dart b/lib/models/walletOptions.dart index 5b43384..931fe49 100644 --- a/lib/models/walletOptions.dart +++ b/lib/models/walletOptions.dart @@ -84,6 +84,10 @@ class WalletOptionsProvider with ChangeNotifier { String _localPubkey; // log.d("$_localDewif $_pin $_pinLenght ${_wallet.derivation}"); + // String mnemo = await DubpRust.getBip32DewifMnemonic( + // dewif: _localDewif, secretCode: _pin); + // log.d(mnemo.toString()); + if ((_localPubkey = await _getPubkeyFromDewif( _localDewif, _pin, _pinLenght, _wallet.derivation)) != 'false') { From 900cfbac9be0df1a456f2fab230ed8953738497a Mon Sep 17 00:00:00 2001 From: poka Date: Mon, 26 Apr 2021 19:45:07 +0200 Subject: [PATCH 07/14] Add shape again do wallets cards (bottom) --- lib/screens/myWallets/walletsHome.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/screens/myWallets/walletsHome.dart b/lib/screens/myWallets/walletsHome.dart index 5105743..6987a2c 100644 --- a/lib/screens/myWallets/walletsHome.dart +++ b/lib/screens/myWallets/walletsHome.dart @@ -158,6 +158,9 @@ class WalletsHome extends StatelessWidget { ), )), ListTile( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.vertical( + bottom: Radius.circular(12))), // contentPadding: const EdgeInsets.only(left: 7.0), tileColor: _repository.id() == defaultWallet.id() ? Color(0xffD28928) From c77b776d599192f5842b7391deff75ff45f9e7bc Mon Sep 17 00:00:00 2001 From: poka Date: Tue, 27 Apr 2021 04:09:20 +0200 Subject: [PATCH 08/14] All onboarding workflow is tested; normalize input mnemonic word to nfkd, no unaccentued anymore --- lib/models/generateWallets.dart | 28 +++------ lib/models/home.dart | 2 +- lib/screens/myWallets/walletsHome.dart | 1 + lib/screens/onBoarding/11.dart | 1 + lib/screens/onBoarding/7.dart | 2 + lib/screens/onBoarding/8.dart | 2 + lib/screens/onBoarding/9.dart | 2 +- pubspec.lock | 7 +++ pubspec.yaml | 1 + test_driver/app_test.dart | 86 +++++++++++++++++++++++++- 10 files changed, 109 insertions(+), 23 deletions(-) diff --git a/lib/models/generateWallets.dart b/lib/models/generateWallets.dart index 3a42498..19e13d9 100644 --- a/lib/models/generateWallets.dart +++ b/lib/models/generateWallets.dart @@ -1,4 +1,3 @@ -import 'dart:convert'; import 'dart:io'; import 'dart:math'; import 'dart:typed_data'; @@ -10,6 +9,7 @@ import 'package:gecko/globals.dart'; import 'package:pdf/pdf.dart'; import 'package:pdf/widgets.dart' as pw; import 'package:printing/printing.dart'; +import "package:unorm_dart/unorm_dart.dart" as unorm; class GenerateWalletsProvider with ChangeNotifier { GenerateWalletsProvider(); @@ -74,26 +74,14 @@ class GenerateWalletsProvider with ChangeNotifier { return _name; } - void checkAskedWord(String value, String _mnemo) { - // nbrWord = getRandomInt(); + void checkAskedWord(String inputWord, String _mnemo) { + final expectedWord = _mnemo.split(' ')[nbrWord]; + final normInputWord = unorm.nfkd(inputWord); - final runesAsked = _mnemo.split(' ')[nbrWord].runes; - List runesAskedUnaccent = []; - for (int i in runesAsked) { - if (i == 768 || i == 769 || i == 770 || i == 771) { - continue; - } else { - runesAskedUnaccent.add(i); - } - } - final String unaccentedAskedWord = - utf8.decode(runesAskedUnaccent).toLowerCase(); - final String unaccentedInputWord = removeDiacritics(value).toLowerCase(); - - log.i("Is $unaccentedAskedWord equal to input $unaccentedInputWord ?"); - if (unaccentedAskedWord == unaccentedInputWord || - value == 'triche' || - value == '3.14') { + log.i("Is $expectedWord equal to input $normInputWord ?"); + if (expectedWord == normInputWord || + inputWord == 'triche' || + inputWord == '3.14') { log.d('Word is OK'); isAskedWordValid = true; askedWordColor = Colors.green[600]; diff --git a/lib/models/home.dart b/lib/models/home.dart index 0338ded..63fc715 100644 --- a/lib/models/home.dart +++ b/lib/models/home.dart @@ -52,7 +52,7 @@ class HomeProvider with ChangeNotifier { int _statusCode = 0; final _client = new HttpClient(); - _client.connectionTimeout = const Duration(milliseconds: 800); + _client.connectionTimeout = const Duration(milliseconds: 1000); do { i++; diff --git a/lib/screens/myWallets/walletsHome.dart b/lib/screens/myWallets/walletsHome.dart index 6987a2c..99e48df 100644 --- a/lib/screens/myWallets/walletsHome.dart +++ b/lib/screens/myWallets/walletsHome.dart @@ -52,6 +52,7 @@ class WalletsHome extends StatelessWidget { ); }), title: Text('Mes portefeuilles', + key: Key('myWallets'), style: TextStyle(color: Colors.grey[850])), backgroundColor: Color(0xffFFD58D), ), diff --git a/lib/screens/onBoarding/11.dart b/lib/screens/onBoarding/11.dart index f622416..f4e1c55 100644 --- a/lib/screens/onBoarding/11.dart +++ b/lib/screens/onBoarding/11.dart @@ -55,6 +55,7 @@ class OnboardingStepThirteen extends StatelessWidget { alignment: Alignment.centerRight, children: [ TextField( + key: Key('generatedPin'), enabled: false, controller: _generateWalletProvider.pin, maxLines: 1, diff --git a/lib/screens/onBoarding/7.dart b/lib/screens/onBoarding/7.dart index 3d685d1..c64def2 100644 --- a/lib/screens/onBoarding/7.dart +++ b/lib/screens/onBoarding/7.dart @@ -126,6 +126,7 @@ Widget sentanceArray(BuildContext context) { '12:...', ], builder: (context, formatedArray) { + // print(formatedArray.data); return Container( padding: EdgeInsets.symmetric(horizontal: 12), child: Container( @@ -173,6 +174,7 @@ Widget arrayCell(dataWord) { Text(dataWord.split(':')[0], style: TextStyle(fontSize: 14)), SizedBox(height: 2), Text(dataWord.split(':')[1], + key: Key('word${dataWord.split(':')[0]}'), style: TextStyle(fontSize: 19, color: Colors.black)), ])); } diff --git a/lib/screens/onBoarding/8.dart b/lib/screens/onBoarding/8.dart index e740527..c98efbd 100644 --- a/lib/screens/onBoarding/8.dart +++ b/lib/screens/onBoarding/8.dart @@ -108,6 +108,7 @@ class OnboardingStepTen extends StatelessWidget { SizedBox(height: isTall ? 70 : 10), if (isTall) Text('${_generateWalletProvider.nbrWord + 1}', + key: Key('askedWord'), style: TextStyle( fontSize: 17, color: Color(0xffD28928), @@ -122,6 +123,7 @@ class OnboardingStepTen extends StatelessWidget { )), width: 430, child: TextFormField( + key: Key('inputWord'), autofocus: true, enabled: !_generateWalletProvider.isAskedWordValid, controller: this.wordController, diff --git a/lib/screens/onBoarding/9.dart b/lib/screens/onBoarding/9.dart index 3c0a876..22e67c9 100644 --- a/lib/screens/onBoarding/9.dart +++ b/lib/screens/onBoarding/9.dart @@ -30,7 +30,7 @@ class OnboardingStepEleven extends StatelessWidget { text: " \n\nVotre code secret chiffre votre trousseau de clefs, ce qui le rend inutilisable par d’autres, par exemple si vous perdez votre téléphone ou si on vous le vole."), ], - textKey: Key('step8'), + textKey: Key('step9'), ), SizedBox(height: isTall ? 50 : 10), Image.asset( diff --git a/pubspec.lock b/pubspec.lock index 8c8924d..7ff5c63 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -899,6 +899,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0" + unorm_dart: + dependency: "direct main" + description: + name: unorm_dart + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0" uuid: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 5c6eeb0..709ee97 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -50,6 +50,7 @@ dependencies: flutter_driver: sdk: flutter test: ^1.16.6 + unorm_dart: ^0.2.0 flutter_icons: android: "ic_launcher" diff --git a/test_driver/app_test.dart b/test_driver/app_test.dart index a1c30e8..e217d0a 100644 --- a/test_driver/app_test.dart +++ b/test_driver/app_test.dart @@ -1,4 +1,6 @@ // Imports the Flutter Driver API. +import 'dart:async'; + import 'package:flutter_driver/flutter_driver.dart'; // import 'package:flutter_test/flutter_test.dart'; import 'package:test/test.dart'; @@ -60,15 +62,97 @@ void main() { "J’ai généré votre phrase de restauration !\nTâchez de la garder bien secrète, car elle permet à quiconque la connaît d’accéder à tous vos portefeuilles."); }); - test('OnBoarding - Generate sentance', ( + test('OnBoarding - Generate sentance and confirme it', ( {timeout: const Duration(seconds: 5)}) async { await driver.tap(find.byValueKey('goStep7')); + print('THE SECOND WORD IS:'); + + while (await driver.getText(find.byValueKey( + 'word1', + )) == + '...') { + print('Waiting for Mnemonic generation...'); + await Future.delayed(const Duration(seconds: 1)); + } + + List words = [for (var i = 1; i <= 13; i += 1) i]; + + for (var j = 1; j < 13; j++) { + words[j] = await driver.getText(find.byValueKey( + 'word$j', + )); + } + + // print word 1, 2 and 12 + // print(words[1] + words[2] + words[12]); + expect( await driver.getText(find.byValueKey( 'step7', )), "C'est le moment de noter votre phrase !"); + + await driver.tap(find.byValueKey('goStep8')); + + final String goodWord = words[int.parse( + await driver.getText( + find.byValueKey( + 'askedWord', + ), + ), + )]; + + await driver.enterText(goodWord); + + await driver.tap(find.byValueKey('goStep9')); + }); + test('OnBoarding - Generate secret code and confirm it', ( + {timeout: const Duration(seconds: 5)}) async { + expect( + await driver.getText(find.byValueKey( + 'step9', + )), + "Super !\n\nJe vais maintenant créer votre code secret. \n\nVotre code secret chiffre votre trousseau de clefs, ce qui le rend inutilisable par d’autres, par exemple si vous perdez votre téléphone ou si on vous le vole."); + + await driver.tap(find.byValueKey('goStep10')); + await driver.tap(find.byValueKey('goStep11')); + + while (await driver.getText(find.byValueKey( + 'generatedPin', + )) == + '') { + print('Waiting for pin code generation...'); + await Future.delayed(const Duration(seconds: 1)); + } + + final pinCode = await driver.getText( + find.byValueKey( + 'generatedPin', + ), + ); + + await driver.tap(find.byValueKey('goStep12')); + await Future.delayed(const Duration(seconds: 1)); + + await driver.enterText(pinCode); + + expect( + await driver.getText(find.byValueKey( + 'step13', + )), + "Top !\n\nVotre trousseau de clef et votre portefeuille ont été créés avec un immense succès.\n\nFélicitations !"); + }); + + test('OnBoarding - Create a derivation and display it', ( + {timeout: const Duration(seconds: 5)}) async { + await driver.tap(find.byValueKey('goWalletHome')); + + expect( + await driver.getText(find.byValueKey( + 'myWallets', + )), + "Mes portefeuilles"); }); }); } From 1a604bfb5a630e931fb519a504eaef36c41708da Mon Sep 17 00:00:00 2001 From: poka Date: Tue, 27 Apr 2021 11:51:14 +0200 Subject: [PATCH 09/14] Improve test mecanic; Continue test until 2nd derivation view --- android/app/src/main/AndroidManifest.xml | 3 +- lib/screens/myWallets/walletsHome.dart | 2 + lib/screens/onBoarding/12.dart | 3 +- lib/screens/onBoarding/7.dart | 1 + test_driver/app_test.dart | 165 ++++++++++++++--------- 5 files changed, 105 insertions(+), 69 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 73c3d1d..3600761 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -9,11 +9,12 @@ - getText(String text) async { + return await driver.getText(find.byValueKey( + text, + )); + } + test('OnBoarding - Open wallets management', ( {timeout: const Duration(seconds: 2)}) async { // await driver.runUnsynchronized(() async { // Needed if we want to manage async drivers @@ -48,12 +60,12 @@ void main() { test('OnBoarding - Go to create restore sentance', ( {timeout: const Duration(seconds: 5)}) async { - await driver.tap(find.byValueKey('goStep1')); - await driver.tap(find.byValueKey('goStep2')); - await driver.tap(find.byValueKey('goStep3')); - await driver.tap(find.byValueKey('goStep4')); - await driver.tap(find.byValueKey('goStep5')); - await driver.tap(find.byValueKey('goStep6')); + await tapOn('goStep1'); + await tapOn('goStep2'); + await tapOn('goStep3'); + await tapOn('goStep4'); + await tapOn('goStep5'); + await tapOn('goStep6'); expect( await driver.getText(find.byValueKey( @@ -64,95 +76,114 @@ void main() { test('OnBoarding - Generate sentance and confirme it', ( {timeout: const Duration(seconds: 5)}) async { - await driver.tap(find.byValueKey('goStep7')); + await tapOn('goStep7'); - print('THE SECOND WORD IS:'); - - while (await driver.getText(find.byValueKey( - 'word1', - )) == - '...') { + while (await getText('word1') == '...') { print('Waiting for Mnemonic generation...'); - await Future.delayed(const Duration(seconds: 1)); + await Future.delayed(const Duration(milliseconds: 100)); } - List words = [for (var i = 1; i <= 13; i += 1) i]; + Future selectWord() async { + List words = [for (var i = 1; i <= 13; i += 1) i]; - for (var j = 1; j < 13; j++) { - words[j] = await driver.getText(find.byValueKey( - 'word$j', - )); + for (var j = 1; j < 13; j++) { + words[j] = await getText('word$j'); + } + expect( + await getText('step7'), "C'est le moment de noter votre phrase !"); + + await tapOn('goStep8'); + await Future.delayed(const Duration(milliseconds: 50)); + + String goodWord = words[int.parse( + await getText('askedWord'), + )]; + + // Enter the expected word + await driver.enterText(goodWord); + + // Check if word is valid + await driver.waitFor(find.text("C'est le bon mot !")); + + // Continue onboarding workflow + await tapOn('goStep9'); } - // print word 1, 2 and 12 - // print(words[1] + words[2] + words[12]); + await selectWord(); - expect( - await driver.getText(find.byValueKey( - 'step7', - )), - "C'est le moment de noter votre phrase !"); + //Go back 2 times to mnemonic generation screen + await goBack(); + await goBack(); + await Future.delayed(const Duration(milliseconds: 100)); - await driver.tap(find.byValueKey('goStep8')); + // Generate 3 times mnemonic + await tapOn('generateMnemonic'); + await tapOn('generateMnemonic'); + await tapOn('generateMnemonic'); + await Future.delayed(const Duration(milliseconds: 500)); - final String goodWord = words[int.parse( - await driver.getText( - find.byValueKey( - 'askedWord', - ), - ), - )]; - - await driver.enterText(goodWord); - - await driver.tap(find.byValueKey('goStep9')); + await selectWord(); }); test('OnBoarding - Generate secret code and confirm it', ( {timeout: const Duration(seconds: 5)}) async { - expect( - await driver.getText(find.byValueKey( - 'step9', - )), + expect(await getText('step9'), "Super !\n\nJe vais maintenant créer votre code secret. \n\nVotre code secret chiffre votre trousseau de clefs, ce qui le rend inutilisable par d’autres, par exemple si vous perdez votre téléphone ou si on vous le vole."); - await driver.tap(find.byValueKey('goStep10')); - await driver.tap(find.byValueKey('goStep11')); + await tapOn('goStep10'); + await tapOn('goStep11'); - while (await driver.getText(find.byValueKey( - 'generatedPin', - )) == - '') { + while (await getText('generatedPin') == '') { print('Waiting for pin code generation...'); - await Future.delayed(const Duration(seconds: 1)); + await Future.delayed(const Duration(milliseconds: 100)); } - final pinCode = await driver.getText( - find.byValueKey( - 'generatedPin', - ), - ); + final pinCode = await getText('generatedPin'); - await driver.tap(find.byValueKey('goStep12')); - await Future.delayed(const Duration(seconds: 1)); + await tapOn('goStep12'); + await Future.delayed(const Duration(milliseconds: 300)); + // //Enter bad secret code + // await driver.enterText('abcde'); + // await tapOn('formKey'); + // await Future.delayed(const Duration(milliseconds: 4000)); + // await tapOn('formKey2'); + + //Enter good secret code await driver.enterText(pinCode); - expect( - await driver.getText(find.byValueKey( - 'step13', - )), + expect(await getText('step13'), "Top !\n\nVotre trousseau de clef et votre portefeuille ont été créés avec un immense succès.\n\nFélicitations !"); }); - test('OnBoarding - Create a derivation and display it', ( + test('My wallets - Create a derivation and display it', ( {timeout: const Duration(seconds: 5)}) async { - await driver.tap(find.byValueKey('goWalletHome')); + await tapOn('goWalletHome'); - expect( - await driver.getText(find.byValueKey( - 'myWallets', - )), - "Mes portefeuilles"); + expect(await getText('myWallets'), "Mes portefeuilles"); + await Future.delayed(const Duration(milliseconds: 300)); + + // Add a second derivation + await tapOn('addDerivation'); + await Future.delayed(const Duration(milliseconds: 50)); + + await driver.enterText('Derivation 2'); + + await tapOn('validDerivation'); + await Future.delayed(const Duration(milliseconds: 300)); + + await driver.tap(find.text('Derivation 2')); + + // Wait 3 seconds at the end + await Future.delayed(const Duration(seconds: 3)); }); }); } + +// Function to go back to previous screen +Future goBack() async { + await Process.run( + 'adb', + ['shell', 'input', 'keyevent', 'KEYCODE_BACK'], + runInShell: true, + ); +} From 347aff705907fef2291582f48f0bfb2ef7d10b44 Mon Sep 17 00:00:00 2001 From: poka Date: Tue, 27 Apr 2021 12:52:43 +0200 Subject: [PATCH 10/14] Fix text for small screens --- lib/screens/onBoarding/8.dart | 14 +++++++------- test_driver/app_test.dart | 5 ++++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/screens/onBoarding/8.dart b/lib/screens/onBoarding/8.dart index c98efbd..56733e2 100644 --- a/lib/screens/onBoarding/8.dart +++ b/lib/screens/onBoarding/8.dart @@ -106,13 +106,13 @@ class OnboardingStepTen extends StatelessWidget { // ), SizedBox(height: isTall ? 70 : 10), - if (isTall) - Text('${_generateWalletProvider.nbrWord + 1}', - key: Key('askedWord'), - style: TextStyle( - fontSize: 17, - color: Color(0xffD28928), - fontWeight: FontWeight.w400)), + + Text('${_generateWalletProvider.nbrWord + 1}', + key: Key('askedWord'), + style: TextStyle( + fontSize: isTall ? 17 : 10, + color: Color(0xffD28928), + fontWeight: FontWeight.w400)), SizedBox(height: isTall ? 10 : 0), Container( decoration: BoxDecoration( diff --git a/test_driver/app_test.dart b/test_driver/app_test.dart index 0511638..b5d99d2 100644 --- a/test_driver/app_test.dart +++ b/test_driver/app_test.dart @@ -93,12 +93,15 @@ void main() { await getText('step7'), "C'est le moment de noter votre phrase !"); await tapOn('goStep8'); - await Future.delayed(const Duration(milliseconds: 50)); + await Future.delayed(const Duration(milliseconds: 200)); String goodWord = words[int.parse( await getText('askedWord'), )]; + // await tapOn('inputWord'); + // await Future.delayed(const Duration(milliseconds: 500)); + // Enter the expected word await driver.enterText(goodWord); From f193f5efacf1dc4b21a9376bc44c0976dcb72f86 Mon Sep 17 00:00:00 2001 From: poka Date: Tue, 27 Apr 2021 23:05:58 +0200 Subject: [PATCH 11/14] Continue to test wallets management views --- lib/models/walletOptions.dart | 4 +- lib/screens/myWallets/unlockingWallet.dart | 2 +- lib/screens/myWallets/walletOptions.dart | 48 ++++---- lib/screens/onBoarding/11.dart | 1 + test_driver/app_test.dart | 121 +++++++++++++++++---- 5 files changed, 134 insertions(+), 42 deletions(-) diff --git a/lib/models/walletOptions.dart b/lib/models/walletOptions.dart index 931fe49..d8aed5f 100644 --- a/lib/models/walletOptions.dart +++ b/lib/models/walletOptions.dart @@ -268,13 +268,13 @@ class WalletOptionsProvider with ChangeNotifier { ), actions: [ TextButton( - child: Text("Non"), + child: Text("Non", key: Key('cancelDeleting')), onPressed: () { Navigator.pop(context, false); }, ), TextButton( - child: Text("Oui"), + child: Text("Oui", key: Key('confirmDeleting')), onPressed: () { Navigator.pop(context, true); }, diff --git a/lib/screens/myWallets/unlockingWallet.dart b/lib/screens/myWallets/unlockingWallet.dart index 615b526..1efba3c 100644 --- a/lib/screens/myWallets/unlockingWallet.dart +++ b/lib/screens/myWallets/unlockingWallet.dart @@ -94,7 +94,7 @@ class UnlockingWallet extends StatelessWidget { fontWeight: FontWeight.bold, ), length: _pinLenght, - obscureText: false, + obscureText: true, obscuringCharacter: '*', animationType: AnimationType.fade, validator: (v) { diff --git a/lib/screens/myWallets/walletOptions.dart b/lib/screens/myWallets/walletOptions.dart index 24a63e6..c4c1ccd 100644 --- a/lib/screens/myWallets/walletOptions.dart +++ b/lib/screens/myWallets/walletOptions.dart @@ -205,6 +205,7 @@ class WalletOptions extends StatelessWidget { ), SizedBox(height: 5), InkWell( + key: Key('displayBalance'), onTap: () { _walletOptions.bluringBalance(); }, @@ -279,6 +280,7 @@ class WalletOptions extends StatelessWidget { }), SizedBox(height: 15 * ratio), GestureDetector( + key: Key('copyPubkey'), onTap: () { Clipboard.setData( ClipboardData(text: _walletOptions.pubkey.text)); @@ -334,6 +336,7 @@ class WalletOptions extends StatelessWidget { ]))), SizedBox(height: 10 * ratio), InkWell( + key: Key('displayHistory'), onTap: () { _historyProvider.isPubkey(ctx, _walletOptions.pubkey.text, goHistory: true); @@ -352,6 +355,7 @@ class WalletOptions extends StatelessWidget { ]))), SizedBox(height: 12 * ratio), InkWell( + key: Key('setDefaultWallet'), onTap: !_walletOptions.isDefaultWallet ? () { defaultWallet = wallet; @@ -381,25 +385,31 @@ class WalletOptions extends StatelessWidget { : Colors.black)), ]))), SizedBox(height: 17 * ratio), - InkWell( - onTap: () async { - await _walletOptions.deleteWallet(context, wallet); - WidgetsBinding.instance.addPostFrameCallback((_) { - _myWalletProvider.listWallets = - _myWalletProvider.readAllWallets(_currentChest); - _myWalletProvider.rebuildWidget(); - }); - }, - child: Row(children: [ - SizedBox(width: 33), - Image.asset( - 'assets/walletOptions/trash.png', - ), - SizedBox(width: 14), - Text('Supprimer ce portefeuille', - style: TextStyle( - fontSize: 20, color: Color(0xffD80000))), - ])), + if (!_walletOptions.isDefaultWallet) + InkWell( + key: Key('deleteWallet'), + onTap: !_walletOptions.isDefaultWallet + ? () async { + await _walletOptions.deleteWallet( + context, wallet); + WidgetsBinding.instance.addPostFrameCallback((_) { + _myWalletProvider.listWallets = + _myWalletProvider + .readAllWallets(_currentChest); + _myWalletProvider.rebuildWidget(); + }); + } + : null, + child: Row(children: [ + SizedBox(width: 33), + Image.asset( + 'assets/walletOptions/trash.png', + ), + SizedBox(width: 14), + Text('Supprimer ce portefeuille', + style: TextStyle( + fontSize: 20, color: Color(0xffD80000))), + ])), ]), ), ), diff --git a/lib/screens/onBoarding/11.dart b/lib/screens/onBoarding/11.dart index f4e1c55..42969df 100644 --- a/lib/screens/onBoarding/11.dart +++ b/lib/screens/onBoarding/11.dart @@ -84,6 +84,7 @@ class OnboardingStepThirteen extends StatelessWidget { width: 400, height: 62, child: ElevatedButton( + key: Key('changeSecretCode'), style: ElevatedButton.styleFrom( elevation: 5, primary: Color(0xffFFD58D), diff --git a/test_driver/app_test.dart b/test_driver/app_test.dart index b5d99d2..81bcebf 100644 --- a/test_driver/app_test.dart +++ b/test_driver/app_test.dart @@ -15,6 +15,7 @@ void main() { // final buttonFinder = find.byValueKey('increment'); FlutterDriver driver; + String pinCode; // Connect to the Flutter driver before running any tests. setUpAll(() async { @@ -80,7 +81,7 @@ void main() { while (await getText('word1') == '...') { print('Waiting for Mnemonic generation...'); - await Future.delayed(const Duration(milliseconds: 100)); + await sleep(100); } Future selectWord() async { @@ -93,15 +94,12 @@ void main() { await getText('step7'), "C'est le moment de noter votre phrase !"); await tapOn('goStep8'); - await Future.delayed(const Duration(milliseconds: 200)); + await sleep(200); String goodWord = words[int.parse( await getText('askedWord'), )]; - // await tapOn('inputWord'); - // await Future.delayed(const Duration(milliseconds: 500)); - // Enter the expected word await driver.enterText(goodWord); @@ -117,13 +115,13 @@ void main() { //Go back 2 times to mnemonic generation screen await goBack(); await goBack(); - await Future.delayed(const Duration(milliseconds: 100)); + await sleep(100); // Generate 3 times mnemonic await tapOn('generateMnemonic'); await tapOn('generateMnemonic'); await tapOn('generateMnemonic'); - await Future.delayed(const Duration(milliseconds: 500)); + await sleep(500); await selectWord(); }); @@ -137,18 +135,22 @@ void main() { while (await getText('generatedPin') == '') { print('Waiting for pin code generation...'); - await Future.delayed(const Duration(milliseconds: 100)); + await sleep(100); } - final pinCode = await getText('generatedPin'); + // Change secret code 4 times + for (int i = 0; i < 4; i++) await tapOn('changeSecretCode'); + + await sleep(500); + pinCode = await getText('generatedPin'); await tapOn('goStep12'); - await Future.delayed(const Duration(milliseconds: 300)); + await sleep(300); // //Enter bad secret code // await driver.enterText('abcde'); // await tapOn('formKey'); - // await Future.delayed(const Duration(milliseconds: 4000)); + // await sleep(1500); // await tapOn('formKey2'); //Enter good secret code @@ -163,21 +165,96 @@ void main() { await tapOn('goWalletHome'); expect(await getText('myWallets'), "Mes portefeuilles"); - await Future.delayed(const Duration(milliseconds: 300)); + await sleep(300); + + // Create a derivation + Future createDerivation(String _name) async { + await tapOn('addDerivation'); + await sleep(100); + + await driver.enterText(_name); + + await tapOn('validDerivation'); + await sleep(300); + } // Add a second derivation - await tapOn('addDerivation'); - await Future.delayed(const Duration(milliseconds: 50)); - - await driver.enterText('Derivation 2'); - - await tapOn('validDerivation'); - await Future.delayed(const Duration(milliseconds: 300)); + await createDerivation('Derivation 2'); + // Go to second derivation options await driver.tap(find.text('Derivation 2')); + await sleep(100); + + // Test options + await tapOn('displayBalance'); + await tapOn('displayHistory'); + await sleep(300); + await goBack(); + await tapOn('displayBalance'); + await sleep(100); + await tapOn('displayBalance'); + await sleep(100); + await tapOn('displayBalance'); + await tapOn('setDefaultWallet'); + await sleep(50); + await tapOn('copyPubkey'); + await driver.waitFor(find + .text('Cette clé publique a été copié dans votre presse-papier.')); + await goBack(); + + // Add a third derivation + await createDerivation('Derivation 3'); + + // Add a fourth derivation + await createDerivation('Derivation 4'); + await sleep(50); + + // Go to third derivation options + await driver.tap(find.text('Derivation 3')); + await sleep(100); + await tapOn('displayBalance'); + + // Delete a derivation + Future deleteWallet(bool _confirm) async { + await tapOn('deleteWallet'); + await sleep(100); + _confirm + ? await tapOn('confirmDeleting') + : await tapOn('cancelDeleting'); + await sleep(300); + } + + // Delete third derivation + await deleteWallet(true); + + // Add derivation 5,6 and 7 + await createDerivation('Derivation 5'); + await createDerivation('Derivation 6'); + await createDerivation('Derivation 7'); + + // Go home and come back to my wallets view + await goBack(); + await sleep(100); + await tapOn('manageWallets'); + await sleep(200); + //Enter secret code + await driver.enterText(pinCode); + await sleep(200); + + // Go to derivation 6 and delete it + await driver.tap(find.text('Derivation 6')); + await sleep(100); + await deleteWallet(true); + + // Go to 2nd derivation and check if it's de default + await driver.tap(find.text('Derivation 2')); + await driver.waitFor(find.text('Ce portefeuille est celui par defaut')); + await tapOn('setDefaultWallet'); + await sleep(100); + await driver.waitFor(find.text('Ce portefeuille est celui par defaut')); // Wait 3 seconds at the end - await Future.delayed(const Duration(seconds: 3)); + await sleep(3000); }); }); } @@ -190,3 +267,7 @@ Future goBack() async { runInShell: true, ); } + +Future sleep(int _time) async { + await Future.delayed(Duration(milliseconds: _time)); +} From 5027b4eb2aa0ff650df005112a8f1cd4dfc958fe Mon Sep 17 00:00:00 2001 From: poka Date: Wed, 28 Apr 2021 23:44:07 +0200 Subject: [PATCH 12/14] Continue tests: All wallets view tested; pubkey search and view tested; All right for now --- lib/models/myWallets.dart | 1 + lib/screens/history.dart | 21 ++-- lib/screens/home.dart | 4 + lib/screens/myWallets/walletOptions.dart | 2 + lib/screens/myWallets/walletsHome.dart | 1 + lib/screens/settings.dart | 1 + test_driver/app_test.dart | 120 ++++++++++++++++++++--- 7 files changed, 132 insertions(+), 18 deletions(-) diff --git a/lib/models/myWallets.dart b/lib/models/myWallets.dart index 7bc4e5f..3ceff88 100644 --- a/lib/models/myWallets.dart +++ b/lib/models/myWallets.dart @@ -172,6 +172,7 @@ class MyWalletsProvider with ChangeNotifier { }, ), TextButton( + key: Key('confirmDeletingAllWallets'), child: Text("Oui"), onPressed: () { Navigator.pop(context, true); diff --git a/lib/screens/history.dart b/lib/screens/history.dart index 3b877ab..a6ca095 100644 --- a/lib/screens/history.dart +++ b/lib/screens/history.dart @@ -169,6 +169,7 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { child: Builder( builder: (context) => Expanded( child: ListView( + key: Key('listTransactions'), controller: scrollController, children: [ SizedBox(height: 20), @@ -222,6 +223,7 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { height: avatarsSize); })), GestureDetector( + key: Key('copyPubkey'), onTap: () { Clipboard.setData(ClipboardData( text: _historyProvider.pubkey)); @@ -288,6 +290,7 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { style: TextStyle(fontSize: 18.0))), SizedBox(height: 20), ElevatedButton( + key: Key('switchPayHistory'), style: ElevatedButton.styleFrom( elevation: 1, primary: Colors.grey[50], // background @@ -401,6 +404,7 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { Widget historyView(context, result) { HistoryProvider _historyProvider = Provider.of(context); + int keyID = 0; return _historyProvider.transBC == null ? Text('Aucune transaction à afficher.') @@ -409,6 +413,7 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { Padding( padding: const EdgeInsets.symmetric(horizontal: 5.0), child: ListTile( + key: Key('transaction${keyID++}'), contentPadding: const EdgeInsets.all(5.0), leading: Text(repository[1].toString(), style: TextStyle( @@ -441,13 +446,15 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { ), // if (_historyProvider.isTheEnd) // What I did before ... if (!_historyProvider.pageInfo['hasPreviousPage']) - Column(children: [ - SizedBox(height: 15), - Text("Début de l'historique.", - textAlign: TextAlign.center, - style: TextStyle(fontSize: 20)), - SizedBox(height: 15) - ]) + Column( + children: [ + SizedBox(height: 15), + Text("Début de l'historique.", + textAlign: TextAlign.center, + style: TextStyle(fontSize: 20)), + SizedBox(height: 15) + ], + ) ]); } } diff --git a/lib/screens/home.dart b/lib/screens/home.dart index e8951dc..1d349a8 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -47,6 +47,7 @@ class HomeScreen extends StatelessWidget { ), ), ListTile( + key: Key('parameters'), title: Text('Paramètres'), onTap: () { Navigator.pop(context); @@ -77,6 +78,7 @@ class HomeScreen extends StatelessWidget { appBar: AppBar( leading: Builder( builder: (context) => IconButton( + key: Key('drawerMenu'), icon: new Icon(Icons.menu, color: Colors.grey[850]), onPressed: () => Scaffold.of(context).openDrawer(), )), @@ -85,6 +87,7 @@ class HomeScreen extends StatelessWidget { Padding( padding: EdgeInsets.symmetric(horizontal: 16), child: IconButton( + key: Key('searchIcon'), icon: _homeProvider.searchIcon, color: Colors.grey[850], onPressed: () { @@ -94,6 +97,7 @@ class HomeScreen extends StatelessWidget { color: Colors.grey[850], ); _homeProvider.appBarTitle = TextField( + key: Key('searchInput'), autofocus: true, controller: _homeProvider.searchQuery, onChanged: (text) { diff --git a/lib/screens/myWallets/walletOptions.dart b/lib/screens/myWallets/walletOptions.dart index c4c1ccd..03944c5 100644 --- a/lib/screens/myWallets/walletOptions.dart +++ b/lib/screens/myWallets/walletOptions.dart @@ -124,6 +124,7 @@ class WalletOptions extends StatelessWidget { SizedBox( width: 260, child: TextField( + key: Key('walletName'), focusNode: _walletOptions.walletNameFocus, enabled: _walletOptions.isEditing, controller: _walletOptions.nameController, @@ -218,6 +219,7 @@ class WalletOptions extends StatelessWidget { SizedBox(width: 0), Column(children: [ InkWell( + key: Key('renameWallet'), onTap: () async { // _walletOptions.isEditing = true; // _walletOptions.reloadBuild(); diff --git a/lib/screens/myWallets/walletsHome.dart b/lib/screens/myWallets/walletsHome.dart index f6038d5..dbd5234 100644 --- a/lib/screens/myWallets/walletsHome.dart +++ b/lib/screens/myWallets/walletsHome.dart @@ -110,6 +110,7 @@ class WalletsHome extends StatelessWidget { List _listWallets = _myWalletProvider.listWallets; return GridView.count( + key: Key('listWallets'), crossAxisCount: 2, childAspectRatio: 1, crossAxisSpacing: 0, diff --git a/lib/screens/settings.dart b/lib/screens/settings.dart index 7912f80..2d466fa 100644 --- a/lib/screens/settings.dart +++ b/lib/screens/settings.dart @@ -80,6 +80,7 @@ class SettingsScreen extends StatelessWidget { height: 100, width: 500, child: ElevatedButton( + key: Key('deleteAllWallets'), style: ElevatedButton.styleFrom( elevation: 5, primary: Colors.redAccent, // background diff --git a/test_driver/app_test.dart b/test_driver/app_test.dart index 81bcebf..26ca793 100644 --- a/test_driver/app_test.dart +++ b/test_driver/app_test.dart @@ -1,12 +1,12 @@ // Imports the Flutter Driver API. import 'dart:async'; import 'dart:io'; - import 'package:flutter_driver/flutter_driver.dart'; -// import 'package:flutter_test/flutter_test.dart'; import 'package:test/test.dart'; +// import 'package:flutter/services.dart'; void main() { + int globalTimeout = 2; group('Gecko App', () { // First, define the Finders and use them to locate widgets from the // test suite. Note: the Strings provided to the `byValueKey` method must @@ -41,18 +41,44 @@ void main() { )); } + Future isPresent(SerializableFinder byValueKey, + {Duration timeout = const Duration(seconds: 1)}) async { + try { + await driver.waitFor(byValueKey, timeout: timeout); + return true; + } catch (exception) { + return false; + } + } + test('OnBoarding - Open wallets management', ( - {timeout: const Duration(seconds: 2)}) async { + {timeout: Timeout.none}) async { // await driver.runUnsynchronized(() async { // Needed if we want to manage async drivers await driver.tap(manageWalletsFinder); + print( + '####################################################################'); + + // If a wallet exist, go to delete theme all + if (!await isPresent(find.byValueKey('goStep1'))) { + await goBack(); + await tapOn('drawerMenu'); + await sleep(300); + await tapOn('parameters'); + await sleep(300); + await tapOn('deleteAllWallets'); + await sleep(300); + await tapOn('confirmDeletingAllWallets'); + await sleep(300); + await driver.tap(manageWalletsFinder); + } + // Get the SerializableFinder for text widget with key 'textOnboarding' SerializableFinder textOnboarding = find.byValueKey( 'textOnboarding', ); - print( - '####################################################################'); + await sleep(100); // Verify onboarding is starting, with text expect(await driver.getText(textOnboarding), @@ -60,7 +86,7 @@ void main() { }); test('OnBoarding - Go to create restore sentance', ( - {timeout: const Duration(seconds: 5)}) async { + {timeout: Timeout.none}) async { await tapOn('goStep1'); await tapOn('goStep2'); await tapOn('goStep3'); @@ -76,7 +102,7 @@ void main() { }); test('OnBoarding - Generate sentance and confirme it', ( - {timeout: const Duration(seconds: 5)}) async { + {timeout: Timeout.none}) async { await tapOn('goStep7'); while (await getText('word1') == '...') { @@ -126,7 +152,7 @@ void main() { await selectWord(); }); test('OnBoarding - Generate secret code and confirm it', ( - {timeout: const Duration(seconds: 5)}) async { + {timeout: Timeout.none}) async { expect(await getText('step9'), "Super !\n\nJe vais maintenant créer votre code secret. \n\nVotre code secret chiffre votre trousseau de clefs, ce qui le rend inutilisable par d’autres, par exemple si vous perdez votre téléphone ou si on vous le vole."); @@ -161,7 +187,7 @@ void main() { }); test('My wallets - Create a derivation and display it', ( - {timeout: const Duration(seconds: 5)}) async { + {timeout: Timeout.none}) async { await tapOn('goWalletHome'); expect(await getText('myWallets'), "Mes portefeuilles"); @@ -252,11 +278,83 @@ void main() { await tapOn('setDefaultWallet'); await sleep(100); await driver.waitFor(find.text('Ce portefeuille est celui par defaut')); + await sleep(300); + + // Display history, copy pubkey, go back and rename wallet name + await tapOn('displayHistory'); + await sleep(400); + await tapOn('copyPubkey'); + await driver.waitFor(find + .text('Cette clé publique a été copié dans votre presse-papier.')); + await sleep(800); + await goBack(); + await sleep(300); + await tapOn('renameWallet'); + await sleep(100); + await tapOn('walletName'); + await sleep(100); + await driver.enterText('Renommage wallet 2'); + await sleep(300); + await tapOn('renameWallet'); + await sleep(400); + await goBack(); + await driver.waitFor(find.text('Renommage wallet 2')); + await createDerivation('Derivation 8'); + await createDerivation('Derivation 9'); + await createDerivation('Derivation 10'); + await createDerivation('Derivation 11'); + await createDerivation('Derivation 12'); + await createDerivation('Derivation 13'); + await createDerivation('Derivation 14'); + await createDerivation('Derivation 15'); + await createDerivation('Derivation 16'); + await createDerivation('Derivation 17'); + await createDerivation('Derivation 18'); + await createDerivation('Derivation 19'); + await createDerivation('Derivation 20'); + await sleep(400); + + // Scroll the wallet screen + await driver.scrollUntilVisible( + find.byValueKey('listWallets'), + find.text('Derivation 20'), + dyScroll: -300.0, + ); + + await driver.waitFor(find.text('Derivation 20')); + await sleep(400); + await driver.tap(find.text('Derivation 20')); + await tapOn('copyPubkey'); + await goBack(); + await goBack(); + await sleep(200); + await tapOn('searchIcon'); + await sleep(400); + await driver.enterText('D2meevcAHFTS2gQMvmRW5Hzi25jDdikk4nC4u1FkwRaU'); + await sleep(100); + await tapOn('copyPubkey'); + await sleep(500); + await tapOn('switchPayHistory'); + await sleep(1200); + // await driver.scrollIntoView(find.byValueKey('listTransactions')); + await driver.scrollUntilVisible( + find.byValueKey('listTransactions'), + find.byValueKey('transaction35'), + dyScroll: -600.0, + ); + await sleep(100); + await tapOn('transaction33'); + await driver.waitFor(find.text('Commentaire:')); + + // Want to paste pubkey copied, but doesn't work actualy with flutter driver: https://github.com/flutter/flutter/issues/47448 + // final ClipboardData pubkeyCopied = + // await Clipboard.getData(Clipboard.kTextPlain); + // await driver.enterText(pubkeyCopied.text); // Wait 3 seconds at the end await sleep(3000); - }); - }); + }, timeout: Timeout(Duration(minutes: globalTimeout))); + }, timeout: Timeout(Duration(minutes: globalTimeout))); } // Function to go back to previous screen From 5c977421674f6a25ddcafe98f5587e56e7422ef0 Mon Sep 17 00:00:00 2001 From: poka Date: Thu, 29 Apr 2021 02:12:14 +0200 Subject: [PATCH 13/14] Test fast keychain generation --- .../myWallets/confirmWalletStorage.dart | 21 ++- lib/screens/myWallets/generateWallets.dart | 2 + lib/screens/settings.dart | 32 ++-- pubspec.lock | 4 +- pubspec.yaml | 2 +- test_driver/app_test.dart | 149 ++++++++++++------ 6 files changed, 139 insertions(+), 71 deletions(-) diff --git a/lib/screens/myWallets/confirmWalletStorage.dart b/lib/screens/myWallets/confirmWalletStorage.dart index 3669fae..614d071 100644 --- a/lib/screens/myWallets/confirmWalletStorage.dart +++ b/lib/screens/myWallets/confirmWalletStorage.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:gecko/models/generateWallets.dart'; import 'package:gecko/models/myWallets.dart'; +import 'package:gecko/models/walletOptions.dart'; import 'package:provider/provider.dart'; // ignore: must_be_immutable @@ -30,6 +31,8 @@ class ConfirmStoreWallet extends StatelessWidget with ChangeNotifier { Provider.of(context); MyWalletsProvider _myWalletProvider = Provider.of(context); + WalletOptionsProvider _walletOptions = + Provider.of(context); final int _currentChest = _myWalletProvider.getCurrentChest(); this._mnemonicController.text = generatedMnemonic; @@ -67,6 +70,7 @@ class ConfirmStoreWallet extends StatelessWidget with ChangeNotifier { fontWeight: FontWeight.w400), )), TextFormField( + key: Key('askedWord'), focusNode: _wordFocus, autofocus: true, enabled: !_generateWalletProvider.isAskedWordValid, @@ -95,6 +99,7 @@ class ConfirmStoreWallet extends StatelessWidget with ChangeNotifier { fontWeight: FontWeight.w400), )), TextFormField( + key: Key('walletName'), focusNode: _generateWalletProvider.walletNameFocus, inputFormatters: [ FilteringTextInputFormatter.allow( @@ -119,6 +124,7 @@ class ConfirmStoreWallet extends StatelessWidget with ChangeNotifier { width: 200, height: 50, child: ElevatedButton( + key: Key('confirmStorage'), style: ElevatedButton.styleFrom( elevation: 12, primary: Colors.green[ @@ -137,14 +143,13 @@ class ConfirmStoreWallet extends StatelessWidget with ChangeNotifier { false; _generateWalletProvider.askedWordColor = Colors.black; - WidgetsBinding.instance - .addPostFrameCallback((_) { - _myWalletProvider.listWallets = - _myWalletProvider - .readAllWallets(_currentChest); - scheduleMicrotask(() { - _myWalletProvider.rebuildWidget(); - }); + _myWalletProvider.listWallets = + _myWalletProvider + .readAllWallets(_currentChest); + _myWalletProvider.getDefaultWallet(); + scheduleMicrotask(() { + _walletOptions.reloadBuild(); + _myWalletProvider.rebuildWidget(); }); Navigator.popUntil( context, ModalRoute.withName('/')); diff --git a/lib/screens/myWallets/generateWallets.dart b/lib/screens/myWallets/generateWallets.dart index 0388245..9847000 100644 --- a/lib/screens/myWallets/generateWallets.dart +++ b/lib/screens/myWallets/generateWallets.dart @@ -71,6 +71,7 @@ class GenerateWalletsScreen extends StatelessWidget { alignment: Alignment.centerRight, children: [ TextField( + key: Key('generatedPin'), enabled: false, controller: _generateWalletProvider.pin, maxLines: 1, @@ -93,6 +94,7 @@ class GenerateWalletsScreen extends StatelessWidget { ), SizedBox(height: 20), ElevatedButton( + key: Key('storeKeychain'), style: ElevatedButton.styleFrom( primary: Color(0xffFFD68E), // background onPrimary: Colors.black, // foreground diff --git a/lib/screens/settings.dart b/lib/screens/settings.dart index 2d466fa..56a2628 100644 --- a/lib/screens/settings.dart +++ b/lib/screens/settings.dart @@ -35,7 +35,7 @@ class SettingsScreen extends StatelessWidget { body: Column(children: [ SizedBox(height: 40), SizedBox( - height: 50, + height: 70, width: 500, child: ElevatedButton( style: ElevatedButton.styleFrom( @@ -52,27 +52,30 @@ class SettingsScreen extends StatelessWidget { if (value == true) {Navigator.pop(context)} }), child: Text("Importer un portefeuille Cesium", - style: TextStyle(fontSize: 15)))), - SizedBox(height: 20), + style: TextStyle(fontSize: 16)))), + SizedBox(height: 30), SizedBox( - height: 50, + height: 70, width: 500, child: ElevatedButton( + key: Key('generateKeychain'), style: ElevatedButton.styleFrom( elevation: 5, primary: Color(0xFFFFCA6F), // background onPrimary: Colors.black, // foreground ), - onPressed: () => Navigator.push( - context, - MaterialPageRoute(builder: (context) { - return GenerateWalletsScreen(); - }), - ).then((value) => { - if (value == true) {Navigator.pop(context)} - }), + onPressed: !_myWallets.checkIfWalletExist() + ? () => Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return GenerateWalletsScreen(); + }), + ).then((value) => { + if (value == true) {Navigator.pop(context)} + }) + : null, child: Text("Générer un nouveau trousseau", - style: TextStyle(fontSize: 15)))), + style: TextStyle(fontSize: 16)))), Expanded( child: Align( alignment: Alignment.bottomCenter, @@ -90,8 +93,7 @@ class SettingsScreen extends StatelessWidget { log.i('Suppression de tous les wallets'), await _myWallets.deleteAllWallet(context) }, - child: Text( - "EFFACER TOUS MES PORTEFEUILLES, LE TEMPS DE L'ALPHA", + child: Text("EFFACER TOUS MES PORTEFEUILLES", style: TextStyle(fontSize: 20)))))), SizedBox(height: 50), ])); diff --git a/pubspec.lock b/pubspec.lock index 7ff5c63..5a6a1aa 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -35,7 +35,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.5.0" + version: "2.6.0" audioplayers: dependency: "direct main" description: @@ -926,7 +926,7 @@ packages: name: vm_service url: "https://pub.dartlang.org" source: hosted - version: "6.1.0+1" + version: "6.2.0" watcher: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 709ee97..ab85da5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -49,7 +49,7 @@ dependencies: audioplayers: ^0.18.1 flutter_driver: sdk: flutter - test: ^1.16.6 + test: ^1.16.8 unorm_dart: ^0.2.0 flutter_icons: diff --git a/test_driver/app_test.dart b/test_driver/app_test.dart index 26ca793..0083329 100644 --- a/test_driver/app_test.dart +++ b/test_driver/app_test.dart @@ -30,17 +30,35 @@ void main() { } }); + // *** Global functions *** // + // Function to tap the widget by key Future tapOn(String key) async { await driver.tap(find.byValueKey(key)); } + // Easy get text Future getText(String text) async { return await driver.getText(find.byValueKey( text, )); } + // Function to go back to previous screen + Future goBack() async { + await Process.run( + 'adb', + ['shell', 'input', 'keyevent', 'KEYCODE_BACK'], + runInShell: true, + ); + } + + // Easy sleep + Future sleep(int _time) async { + await Future.delayed(Duration(milliseconds: _time)); + } + + // Test if widget exist on screen, return a boolean Future isPresent(SerializableFinder byValueKey, {Duration timeout = const Duration(seconds: 1)}) async { try { @@ -51,6 +69,61 @@ void main() { } } + // Create a derivation + Future createDerivation(String _name) async { + await tapOn('addDerivation'); + await sleep(100); + + await driver.enterText(_name); + + await tapOn('validDerivation'); + await sleep(300); + } + + // Delete a derivation + Future deleteWallet(bool _confirm) async { + await tapOn('deleteWallet'); + await sleep(100); + _confirm ? await tapOn('confirmDeleting') : await tapOn('cancelDeleting'); + await sleep(300); + } + + // Delete all wallets + Future deleteAllWallets() async { + await tapOn('drawerMenu'); + await sleep(300); + await tapOn('parameters'); + await sleep(300); + await tapOn('deleteAllWallets'); + await sleep(300); + await tapOn('confirmDeletingAllWallets'); + await sleep(300); + } + + // Fast creation of new Keychain + Future createNewKeychain(String name) async { + await tapOn('drawerMenu'); + await sleep(300); + await tapOn('parameters'); + await sleep(300); + await tapOn('generateKeychain'); + while (await getText('generatedPin') == '') { + print('Waiting for pin code generation...'); + await sleep(100); + } + pinCode = await getText('generatedPin'); + await tapOn('storeKeychain'); + await sleep(100); + await driver.enterText('triche'); + await tapOn('walletName'); + await driver.enterText(name); + await tapOn('confirmStorage'); + await sleep(300); + return pinCode; + } + + // *** Begin of tests *** // + test('OnBoarding - Open wallets management', ( {timeout: Timeout.none}) async { // await driver.runUnsynchronized(() async { // Needed if we want to manage async drivers @@ -62,14 +135,9 @@ void main() { // If a wallet exist, go to delete theme all if (!await isPresent(find.byValueKey('goStep1'))) { await goBack(); - await tapOn('drawerMenu'); - await sleep(300); - await tapOn('parameters'); - await sleep(300); - await tapOn('deleteAllWallets'); - await sleep(300); - await tapOn('confirmDeletingAllWallets'); - await sleep(300); + + await deleteAllWallets(); + await driver.tap(manageWalletsFinder); } @@ -186,24 +254,13 @@ void main() { "Top !\n\nVotre trousseau de clef et votre portefeuille ont été créés avec un immense succès.\n\nFélicitations !"); }); - test('My wallets - Create a derivation and display it', ( + test('My wallets - Create a derivations, open thems, tap all buttons', ( {timeout: Timeout.none}) async { await tapOn('goWalletHome'); expect(await getText('myWallets'), "Mes portefeuilles"); await sleep(300); - // Create a derivation - Future createDerivation(String _name) async { - await tapOn('addDerivation'); - await sleep(100); - - await driver.enterText(_name); - - await tapOn('validDerivation'); - await sleep(300); - } - // Add a second derivation await createDerivation('Derivation 2'); @@ -240,19 +297,11 @@ void main() { await sleep(100); await tapOn('displayBalance'); - // Delete a derivation - Future deleteWallet(bool _confirm) async { - await tapOn('deleteWallet'); - await sleep(100); - _confirm - ? await tapOn('confirmDeleting') - : await tapOn('cancelDeleting'); - await sleep(300); - } - // Delete third derivation await deleteWallet(true); + }); + test('My wallets - Extra tests', ({timeout: Timeout.none}) async { // Add derivation 5,6 and 7 await createDerivation('Derivation 5'); await createDerivation('Derivation 6'); @@ -314,7 +363,7 @@ void main() { await createDerivation('Derivation 20'); await sleep(400); - // Scroll the wallet screen + // Scroll the wallet screen until Derivation 20 and open it await driver.scrollUntilVisible( find.byValueKey('listWallets'), find.text('Derivation 20'), @@ -325,6 +374,10 @@ void main() { await sleep(400); await driver.tap(find.text('Derivation 20')); await tapOn('copyPubkey'); + }); + + test('Search - Search Pi profile, navigate in history transactions', ( + {timeout: Timeout.none}) async { await goBack(); await goBack(); await sleep(200); @@ -351,21 +404,27 @@ void main() { // await Clipboard.getData(Clipboard.kTextPlain); // await driver.enterText(pubkeyCopied.text); + await sleep(300); + }, timeout: Timeout(Duration(minutes: globalTimeout))); + + test('Wallet generation - Fast wallets generations', ( + {timeout: Timeout.none}) async { + await goBack(); + await goBack(); + await deleteAllWallets(); + await sleep(100); + final String pincode = await createNewKeychain('Fast wallet'); + await sleep(100); + await tapOn('manageWallets'); + await sleep(200); + await driver.enterText(pincode); + await sleep(100); + await createDerivation('Derivation 2'); + await sleep(100); + await driver.tap(find.text('Fast wallet')); + await driver.waitFor(find.text('Fast wallet')); // Wait 3 seconds at the end await sleep(3000); - }, timeout: Timeout(Duration(minutes: globalTimeout))); + }); }, timeout: Timeout(Duration(minutes: globalTimeout))); } - -// Function to go back to previous screen -Future goBack() async { - await Process.run( - 'adb', - ['shell', 'input', 'keyevent', 'KEYCODE_BACK'], - runInShell: true, - ); -} - -Future sleep(int _time) async { - await Future.delayed(Duration(milliseconds: _time)); -} From 0f6b0e193ddfa034263aea9767060ed889ad2077 Mon Sep 17 00:00:00 2001 From: poka Date: Fri, 30 Apr 2021 22:51:52 +0200 Subject: [PATCH 14/14] change docker ci image to v.0.0.7 --- .gitlab-ci.yml | 4 ++-- pubspec.lock | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 64552f7..e050d5f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,7 +5,7 @@ stages: - package .env: - image: axiomteam/gecko-ci:v0.0.6 + image: axiomteam/gecko-ci:v0.0.7 tags: - p2plegal before_script: @@ -24,7 +24,7 @@ format: - cargo fmt -- --version - cargo fmt -- --check - flutter format --set-exit-if-changed lib packages/dubp_rs/lib/dubp.dart - + build_and_test: extends: .env rules: diff --git a/pubspec.lock b/pubspec.lock index 5a6a1aa..45f9583 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -35,7 +35,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.6.0" + version: "2.5.0" audioplayers: dependency: "direct main" description: @@ -140,7 +140,7 @@ packages: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.0.0" dubp: dependency: "direct main" description: @@ -926,7 +926,7 @@ packages: name: vm_service url: "https://pub.dartlang.org" source: hosted - version: "6.2.0" + version: "6.1.0+1" watcher: dependency: transitive description: