From 2f3bbbe78755ce1104d4570d6d2d052fc31775c5 Mon Sep 17 00:00:00 2001 From: Janusz Janus Date: Thu, 16 Jan 2025 13:30:32 +0100 Subject: [PATCH] test(cat-voices): Store and restore seeds during onboarding create (#1490) --- .../pageobject/common_page.dart | 7 +- .../pageobject/onboarding_page.dart | 469 +++++++++++---- .../pageobject/spaces_drawer_page.dart | 19 +- .../integration_test/suites/account_test.dart | 3 +- .../integration_test/suites/app_test.dart | 15 +- .../suites/onboarding_test.dart | 561 +++++++++++++++++- .../types/password_validation_states.dart | 5 + .../integration_test/utils/constants.dart | 9 + .../utils/selector_utils.dart | 6 +- .../integration_test/utils/test_context.dart | 42 ++ .../finish_account_creation_panel.dart | 2 + .../recover/recover_method_panel.dart | 5 + .../wallet_link/stage/intro_panel.dart | 1 + .../stage/select_wallet_panel.dart | 2 + .../pages/registration/widgets/next_step.dart | 1 + .../widgets/registration_tile.dart | 1 + .../widgets/unlock_password_form.dart | 2 + .../voices_password_strength_indicator.dart | 2 + .../seed_phrase/seed_phrases_sequencer.dart | 1 + .../separators/voices_text_divider.dart | 1 + .../widgets/text_field/voices_text_field.dart | 1 + 21 files changed, 987 insertions(+), 168 deletions(-) create mode 100644 catalyst_voices/apps/voices/integration_test/types/password_validation_states.dart create mode 100644 catalyst_voices/apps/voices/integration_test/utils/constants.dart create mode 100644 catalyst_voices/apps/voices/integration_test/utils/test_context.dart diff --git a/catalyst_voices/apps/voices/integration_test/pageobject/common_page.dart b/catalyst_voices/apps/voices/integration_test/pageobject/common_page.dart index 6732e683fb6..12296dfb200 100644 --- a/catalyst_voices/apps/voices/integration_test/pageobject/common_page.dart +++ b/catalyst_voices/apps/voices/integration_test/pageobject/common_page.dart @@ -1,8 +1,9 @@ import 'package:flutter/material.dart'; class CommonPage { - static const decoratorData = Key('DecoratorData'); - static const decoratorIconBefore = Key('DecoratorIconBefore'); - static const decoratorIconAfter = Key('DecoratorIconAfter'); + static const decorData = Key('DecoratorData'); + static const decorIconBefore = Key('DecoratorIconBefore'); + static const decorIconAfter = Key('DecoratorIconAfter'); static const dialogCloseButton = Key('DialogCloseButton'); + static const voicesTextField = Key('VoicesTextField'); } diff --git a/catalyst_voices/apps/voices/integration_test/pageobject/onboarding_page.dart b/catalyst_voices/apps/voices/integration_test/pageobject/onboarding_page.dart index 5a10edf034b..ab8291b3988 100644 --- a/catalyst_voices/apps/voices/integration_test/pageobject/onboarding_page.dart +++ b/catalyst_voices/apps/voices/integration_test/pageobject/onboarding_page.dart @@ -2,8 +2,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:patrol_finders/patrol_finders.dart'; +import '../types/password_validation_states.dart'; import '../types/registration_state.dart'; import '../utils/selector_utils.dart'; +import '../utils/test_context.dart'; import '../utils/translations_utils.dart'; import 'common_page.dart'; @@ -26,6 +28,32 @@ class OnboardingPage { static const seedPhraseStoredCheckbox = Key('SeedPhraseStoredCheckbox'); static const uploadKeyButton = Key('UploadKeyButton'); static const resetButton = Key('ResetButton'); + static const seedPhrasesPicker = Key('SeedPhrasesPicker'); + static const nextStepTitle = Key('NextStepTitle'); + static const nextStepBody = Key('NextStepBody'); + static const passwordInputField = Key('PasswordInputField'); + static const passwordConfirmInputField = Key('PasswordConfirmInputField'); + static const passwordStrengthIndicator = Key('PasswordStrengthIndicator'); + static const passwordStrengthLabel = Key('PasswordStrengthLabel'); + static const finishAccountCreationPanel = Key('FinishAccountCreationPanel'); + static const finishAccountKeychainCreated = + Key('StepRegistrationProgressStepGroup.createKeychainRowKey'); + static const finishAccountLinkWallet = + Key('StepRegistrationProgressStepGroup.linkWalletRowKey'); + static const finishAccountAccountComplete = + Key('StepRegistrationProgressStepGroup.accountCompletedRowKey'); + static const linkWalletAndRolesButton = Key('LinkWalletAndRolesButton'); + static const chooseCardanoWalletButton = Key('ChooseCardanoWalletButton'); + static const seeAllSupportedWalletsBtn = Key('SeeAllSupportedWalletsButton'); + static const walletsLinkBuilder = Key('WalletsLinkBuilder'); + static const recoverKeychainMethodsTitle = Key('RecoverKeychainMethodsTitle'); + static const keychainNotFoundIndicator = Key('KeychainNotFoundIndicator'); + static const onDeviceKeychainsWidget = Key('BlocOnDeviceKeychains'); + static const recoverKeychainMethodsSubtitle = + Key('RecoverKeychainMethodsSubtitle'); + static const recoverKeychainMethodsListTitle = + Key('RecoverKeychainMethodsListTitle'); + static const registrationTileTitle = Key('RegistrationTileTitle'); static Future writedownSeedPhraseNumber( PatrolTester $, @@ -37,37 +65,41 @@ class OnboardingPage { return int.parse(rawNumber!.split('.').first); } - static Future writedownSeedPhraseWord( + static Future writedownSeedPhraseWord( PatrolTester $, int index, ) async { - final rawNumber = + final rawWord = $(Key('SeedPhrase${index}CellKey')).$(const Key('SeedPhraseWord')).text; - return int.parse(rawNumber!.split('.').first); + return rawWord!; } - static Future inputSeedPhraseCompleterWord( + static Future inputSeedPhraseCompleterText( PatrolTester $, int index, ) async { - final seedWord = await getChildNodeText( - $, - $(Key('CompleterSeedPhrase${index}CellKey')).$(CommonPage.decoratorData), - ); + final seedWord = $(Key('CompleterSeedPhrase${index}CellKey')) + .$(CommonPage.decorData) + .$(Text) + .text; return seedWord!; } - static Future inputSeedPhrasePickerWord( + static Future inputSeedPhrasePickerText( PatrolTester $, int index, ) async { - final seedWord = await getChildNodeText( - $, - $(Key('PickerSeedPhrase${index + 1}CellKey')), - ); + final seedWord = $(Key('PickerSeedPhrase${index + 1}CellKey')).$(Text).text; return seedWord!; } + static Future inputSeedPhrasePicker( + PatrolTester $, + String word, + ) async { + return $(seedPhrasesPicker).$(find.text(word)); + } + static Future infoPartHeaderTitleText(PatrolTester $) async { return $(registrationInfoPanel).$(headerTitle).text; } @@ -86,44 +118,25 @@ class OnboardingPage { .waitUntilVisible(); } - static Future getChildNodeText( - PatrolTester $, - FinderBase parent, - ) async { - final child = find.descendant( - of: parent, - matching: find.byType(Text), - ); - return $(child).text; - } - static Finder infoPartTaskPicture(PatrolTester $) { - final child = find.descendant( - of: $(registrationInfoPanel).$(registrationInfoPictureContainer), - matching: find.byType(IconTheme), - ); - return child; + return $(registrationInfoPanel) + .$(registrationInfoPictureContainer) + .$(IconTheme); } - static void voicesFilledButtonIsEnabled( + static void voicesButtonIsEnabled( PatrolTester $, Key button, ) { - final child = find.descendant( - of: $(button), - matching: find.byType(FilledButton), - ); + final child = $(button).$(FilledButton); SelectorUtils.isEnabled($, $(child)); } - static void voicesFilledButtonIsDisabled( + static void voicesButtonIsDisabled( PatrolTester $, Key button, ) { - final child = find.descendant( - of: $(button), - matching: find.byType(FilledButton), - ); + final child = $(button).$(FilledButton); SelectorUtils.isDisabled($, $(child)); } @@ -172,10 +185,7 @@ class OnboardingPage { expect(await infoPartHeaderTitleText($), T.get('Get Started')); expect(infoPartTaskPicture($), findsOneWidget); expect( - await getChildNodeText( - $, - $(registrationInfoPanel).$(CommonPage.decoratorData), - ), + $(registrationInfoPanel).$(CommonPage.decorData).$(Text).text, T.get('Learn More'), ); break; @@ -185,10 +195,7 @@ class OnboardingPage { expect(infoPartTaskPicture($), findsOneWidget); expect($(progressBar), findsOneWidget); expect( - await getChildNodeText( - $, - $(registrationInfoPanel).$(CommonPage.decoratorData), - ), + $(registrationInfoPanel).$(CommonPage.decorData).$(Text).text, T.get('Learn More'), ); break; @@ -208,10 +215,7 @@ class OnboardingPage { expect(infoPartTaskPicture($), findsOneWidget); expect($(progressBar), findsOneWidget); expect( - await getChildNodeText( - $, - $(registrationInfoPanel).$(CommonPage.decoratorData), - ), + $(registrationInfoPanel).$(CommonPage.decorData).$(Text).text, T.get('Learn More'), ); break; @@ -220,12 +224,10 @@ class OnboardingPage { expect(infoPartTaskPicture($), findsOneWidget); expect($(progressBar), findsOneWidget); expect( - await getChildNodeText( - $, - $(registrationInfoPanel).$(CommonPage.decoratorData), - ), + $(registrationInfoPanel).$(CommonPage.decorData).$(Text).text, T.get('Learn More'), ); + break; case RegistrationState.keychainCreateMnemonicInput: expect(await infoPartHeaderTitleText($), T.get('Catalyst Keychain')); expect( @@ -241,33 +243,95 @@ class OnboardingPage { expect(infoPartTaskPicture($), findsOneWidget); expect($(progressBar), findsOneWidget); expect( - await getChildNodeText( - $, - $(registrationInfoPanel).$(CommonPage.decoratorData), - ), + $(registrationInfoPanel).$(CommonPage.decorData).$(Text).text, T.get('Learn More'), ); break; case RegistrationState.keychainCreateMnemonicVerified: - throw UnimplementedError(); + expect(await infoPartHeaderTitleText($), T.get('Catalyst Keychain')); + //temporary: check for specific picture (green checked icon) + expect(infoPartTaskPicture($), findsOneWidget); + expect($(progressBar), findsOneWidget); + expect( + $(registrationInfoPanel).$(CommonPage.decorData).$(Text).text, + T.get('Learn More'), + ); + break; + case RegistrationState.passwordInfo: + expect(await infoPartHeaderTitleText($), T.get('Catalyst Keychain')); + //temporary: check for specific picture (locked icon) + expect(infoPartTaskPicture($), findsOneWidget); + expect($(progressBar), findsOneWidget); + expect( + $(registrationInfoPanel).$(CommonPage.decorData).$(Text).text, + T.get('Learn More'), + ); + break; + case RegistrationState.passwordInput: + expect(await infoPartHeaderTitleText($), T.get('Catalyst Keychain')); + expect( + await infoPartHeaderSubtitleText($), + T.get('Catalyst unlock password'), + ); + expect( + await infoPartHeaderBodyText($), + T.get( + 'Please provide a password for your Catalyst Keychain.', + ), + ); + //temporary: check for specific picture (locked icon) + expect(infoPartTaskPicture($), findsOneWidget); + expect($(progressBar), findsOneWidget); + expect( + $(registrationInfoPanel).$(CommonPage.decorData).$(Text).text, + T.get('Learn More'), + ); + break; + case RegistrationState.keychainCreateSuccess: + expect(await infoPartHeaderTitleText($), T.get('Catalyst Keychain')); + //temporary: check for specific picture (green key locked icon) + expect(infoPartTaskPicture($), findsOneWidget); + expect($(progressBar), findsOneWidget); + expect( + $(registrationInfoPanel).$(CommonPage.decorData).$(Text).text, + T.get('Learn More'), + ); + break; case RegistrationState.keychainRestoreChoice: - throw UnimplementedError(); + expect( + await infoPartHeaderTitleText($), + T.get('Restore Catalyst keychain'), + ); + expect(infoPartTaskPicture($), findsOneWidget); + expect( + $(registrationInfoPanel).$(CommonPage.decorData).$(Text).text, + T.get('Learn More'), + ); + break; case RegistrationState.keychainRestoreMnemonicInfo: throw UnimplementedError(); case RegistrationState.keychainRestoreMnemonicInput: throw UnimplementedError(); case RegistrationState.keychainRestoreSuccess: throw UnimplementedError(); - case RegistrationState.passwordInfo: - throw UnimplementedError(); - case RegistrationState.passwordInput: - throw UnimplementedError(); - case RegistrationState.keychainCreateSuccess: - throw UnimplementedError(); case RegistrationState.linkWalletInfo: - throw UnimplementedError(); case RegistrationState.linkWalletSelect: - throw UnimplementedError(); + expect( + await infoPartHeaderTitleText($), + T.get('Link keys to your Catalyst Keychain'), + ); + expect( + await infoPartHeaderSubtitleText($), + T.get('Link your Cardano wallet'), + ); + //temporary: check for specific picture (blue key icon) + expect(infoPartTaskPicture($), findsOneWidget); + expect($(progressBar), findsOneWidget); + expect( + $(registrationInfoPanel).$(CommonPage.decorData).$(Text).text, + T.get('Learn More'), + ); + break; case RegistrationState.linkWalletSuccess: throw UnimplementedError(); case RegistrationState.rolesSelect: @@ -290,17 +354,11 @@ class OnboardingPage { switch (step) { case RegistrationState.getStarted: expect( - await getChildNodeText( - $, - $(registrationDetailsPanel).$(registrationDetailsTitle), - ), + $(registrationDetailsPanel).$(registrationDetailsTitle).$(Text).text, T.get('Welcome to Catalyst'), ); expect( - await getChildNodeText( - $, - $(registrationDetailsPanel).$(registrationDetailsBody), - ), + $(registrationDetailsPanel).$(registrationDetailsBody).$(Text).text, isNotEmpty, ); expect( @@ -312,17 +370,11 @@ class OnboardingPage { break; case RegistrationState.createKeychainInfo: expect( - await getChildNodeText( - $, - $(registrationDetailsPanel).$(registrationDetailsTitle), - ), + $(registrationDetailsPanel).$(registrationDetailsTitle).$(Text).text, T.get('Create your Catalyst Keychain'), ); expect( - await getChildNodeText( - $, - $(registrationDetailsPanel).$(registrationDetailsBody), - ), + $(registrationDetailsPanel).$(registrationDetailsBody).$(Text).text, isNotEmpty, ); expect(await detailsPartCreateKeychainBtn($), findsOneWidget); @@ -330,17 +382,11 @@ class OnboardingPage { break; case RegistrationState.keychainCreated: expect( - await getChildNodeText( - $, - $(registrationDetailsPanel).$(registrationDetailsTitle), - ), + $(registrationDetailsPanel).$(registrationDetailsTitle).$(Text).text, T.get('Great! Your Catalyst Keychain 
has been created.'), ); expect( - await getChildNodeText( - $, - $(registrationDetailsPanel).$(registrationDetailsBody), - ), + $(registrationDetailsPanel).$(registrationDetailsBody).$(Text).text, isNotEmpty, ); expect($(backButton), findsOneWidget); @@ -350,15 +396,12 @@ class OnboardingPage { await writedownSeedPhrasesAreDisplayed($); expect($(downloadSeedPhraseButton), findsOneWidget); expect( - await getChildNodeText( - $, - $(downloadSeedPhraseButton).$(CommonPage.decoratorData), - ), + $(downloadSeedPhraseButton).$(CommonPage.decorData).$(Text).text, T.get('Download Catalyst key'), ); expect($(seedPhraseStoredCheckbox), findsOneWidget); expect( - await getChildNodeText($, $(seedPhraseStoredCheckbox)), + $(seedPhraseStoredCheckbox).$(Text).text, T.get('I have written down/downloaded my 12 words'), ); expect($(backButton), findsOneWidget); @@ -366,17 +409,11 @@ class OnboardingPage { break; case RegistrationState.keychainCreateMnemonicInputInfo: expect( - await getChildNodeText( - $, - $(registrationDetailsPanel).$(registrationDetailsTitle), - ), + $(registrationDetailsPanel).$(registrationDetailsTitle).$(Text).text, T.get('Check your Catalyst security keys'), ); expect( - await getChildNodeText( - $, - $(registrationDetailsPanel).$(registrationDetailsBody), - ), + $(registrationDetailsPanel).$(registrationDetailsBody).$(Text).text, isNotEmpty, ); break; @@ -384,35 +421,154 @@ class OnboardingPage { await inputSeedPhrasesAreDisplayed($); expect($(uploadKeyButton), findsOneWidget); expect( - await getChildNodeText( - $, - $(uploadKeyButton).$(CommonPage.decoratorData), - ), + $(uploadKeyButton).$(CommonPage.decorData).$(Text).text, T.get('Upload Catalyst Key'), ); expect($(backButton), findsOneWidget); expect($(nextButton), findsOneWidget); break; case RegistrationState.keychainCreateMnemonicVerified: - throw UnimplementedError(); + await $(registrationDetailsPanel) + .$(registrationDetailsTitle) + .waitUntilVisible(); + expect( + $(registrationDetailsPanel).$(registrationDetailsTitle).$(Text).text, + T.get("Nice job! You've successfully verified the seed phrase for " + 'your keychain.'), + ); + expect( + $(registrationDetailsPanel).$(registrationDetailsBody).$(Text).text, + isNotEmpty, + ); + expect( + $(nextStepTitle).$(Text).text, + T.get('Your next step'), + ); + expect( + $(nextStepBody).text, + T.get('Now let’s set your Unlock password ' + 'for this device!'), + ); + expect($(backButton), findsOneWidget); + expect($(nextButton), findsOneWidget); + break; + case RegistrationState.passwordInfo: + expect( + $(registrationDetailsPanel).$(registrationDetailsTitle).$(Text).text, + T.get('Set your Catalyst unlock password 
for this device'), + ); + expect( + $(registrationDetailsPanel).$(registrationDetailsBody).$(Text).text, + isNotEmpty, + ); + expect($(backButton), findsOneWidget); + expect($(nextButton), findsOneWidget); + break; + case RegistrationState.passwordInput: + expect( + $(registrationDetailsPanel).$(passwordInputField).$(Text).text, + T.get('Enter password'), + ); + expect( + $(registrationDetailsPanel).$(passwordConfirmInputField).$(Text).text, + T.get('Confirm password'), + ); + expect($(passwordStrengthLabel), findsNothing); + expect($(passwordStrengthIndicator), findsNothing); + expect($(backButton), findsOneWidget); + expect($(nextButton), findsOneWidget); + OnboardingPage.voicesButtonIsDisabled($, OnboardingPage.nextButton); + break; + case RegistrationState.keychainCreateSuccess: + expect( + $(finishAccountCreationPanel).$(Text).text, + T.get('Congratulations your Catalyst 
Keychain is created!'), + ); + expect( + $(finishAccountKeychainCreated).$(Text).text, + T.get('Catalyst Keychain created'), + ); + expect( + $(finishAccountLinkWallet).$(Text).text, + T.get('Link Cardano Wallet & Roles'), + ); + expect( + $(finishAccountAccountComplete).$(Text).text, + T.get('Catalyst account creation completed!'), + ); + expect( + $(nextStepTitle).$(Text).text, + T.get('Your next step'), + ); + expect( + $(nextStepBody).text, + T.get('In the next step you write your Catalyst roles and 
account ' + 'to the Cardano Mainnet.'), + ); + expect( + $(linkWalletAndRolesButton).$(Text).text, + T.get('Link your Cardano Wallet & Roles'), + ); + break; case RegistrationState.keychainRestoreChoice: - throw UnimplementedError(); + expect( + $(recoverKeychainMethodsTitle).text, + T.get('Restore your Catalyst Keychain'), + ); + expect( + $(onDeviceKeychainsWidget).$(keychainNotFoundIndicator).$(Text).text, + T.get('No Catalyst Keychain found
on this device.'), + ); + expect( + $(recoverKeychainMethodsSubtitle).text, + T.get('Not to worry, in the next step you can choose the recovery ' + 'option that applies to you for this device!'), + ); + expect( + $(recoverKeychainMethodsListTitle).text, + T.get('How do you want Restore your Catalyst Keychain?'), + ); + expect( + $(registrationTileTitle).text, + T.get('12 security words'), + ); + break; case RegistrationState.keychainRestoreMnemonicInfo: throw UnimplementedError(); case RegistrationState.keychainRestoreMnemonicInput: throw UnimplementedError(); case RegistrationState.keychainRestoreSuccess: throw UnimplementedError(); - case RegistrationState.passwordInfo: - throw UnimplementedError(); - case RegistrationState.passwordInput: - throw UnimplementedError(); - case RegistrationState.keychainCreateSuccess: - throw UnimplementedError(); case RegistrationState.linkWalletInfo: - throw UnimplementedError(); + expect( + $(registrationDetailsPanel).$(registrationDetailsTitle).$(Text).text, + T.get('Link Cardano Wallet & Catalyst Roles to you Catalyst ' + 'Keychain.'), + ); + expect( + $(registrationDetailsPanel).$(registrationDetailsBody).$(Text).text, + isNotEmpty, + ); + expect( + $(chooseCardanoWalletButton).$(Text).text, + T.get('Choose Cardano Wallet'), + ); + break; case RegistrationState.linkWalletSelect: - throw UnimplementedError(); + expect( + $(registrationDetailsPanel).$(registrationDetailsTitle).$(Text).text, + T.get( + 'Select the Cardano wallet to link\nto your Catalyst Keychain.', + ), + ); + expect( + $(registrationDetailsPanel).$(registrationDetailsBody).$(Text).text, + isNotEmpty, + ); + expect($(walletsLinkBuilder), findsOneWidget); + expect($(backButton), findsOneWidget); + expect($(seeAllSupportedWalletsBtn), findsOneWidget); + break; case RegistrationState.linkWalletSuccess: throw UnimplementedError(); case RegistrationState.rolesSelect: @@ -437,8 +593,77 @@ class OnboardingPage { static Future inputSeedPhrasesAreDisplayed(PatrolTester $) async { for (var i = 0; i < 12; i++) { - expect(await inputSeedPhrasePickerWord($, i), isNotEmpty); - expect(await inputSeedPhraseCompleterWord($, i), isNotEmpty); + expect(await inputSeedPhrasePickerText($, i), isNotEmpty); + expect(await inputSeedPhraseCompleterText($, i), isNotEmpty); + } + } + + static Future storeSeedPhrases(PatrolTester $) async { + for (var i = 0; i < 12; i++) { + final v1 = await writedownSeedPhraseWord($, i); + TestContext.save(key: 'word$i', value: v1); + } + } + + static Future enterStoredSeedPhrases(PatrolTester $) async { + for (var i = 0; i < 12; i++) { + await inputSeedPhrasePicker($, TestContext.get(key: 'word$i')).tap(); + } + } + + static Future enterPassword(PatrolTester $, String password) async { + await $(passwordInputField).enterText(password); + } + + static Future enterPasswordConfirm( + PatrolTester $, + String password, + ) async { + await $(passwordConfirmInputField).enterText(password); + } + + static void checkValidationIndicator( + PatrolTester $, + PasswordValidationStatus validationStatus, + ) { + expect($(passwordStrengthLabel), findsOneWidget); + + switch (validationStatus) { + case PasswordValidationStatus.weak: + expect( + $(passwordStrengthLabel).text, + T.get('Weak password strength'), + ); + break; + case PasswordValidationStatus.normal: + expect( + $(passwordStrengthLabel).text, + T.get('Normal password strength'), + ); + break; + case PasswordValidationStatus.good: + expect( + $(passwordStrengthLabel).text, + T.get('Good password strength'), + ); + break; + } + } + + static void passwordConfirmErrorIconIsShown( + PatrolTester $, { + bool reverse = false, + }) { + if (reverse) { + expect( + $(registrationDetailsPanel).$(CommonPage.voicesTextField).$(Icon), + findsNothing, + ); + } else { + expect( + $(registrationDetailsPanel).$(CommonPage.voicesTextField).$(Icon), + findsOneWidget, + ); } } } diff --git a/catalyst_voices/apps/voices/integration_test/pageobject/spaces_drawer_page.dart b/catalyst_voices/apps/voices/integration_test/pageobject/spaces_drawer_page.dart index b355c211485..2c03468c3f7 100644 --- a/catalyst_voices/apps/voices/integration_test/pageobject/spaces_drawer_page.dart +++ b/catalyst_voices/apps/voices/integration_test/pageobject/spaces_drawer_page.dart @@ -116,11 +116,10 @@ class SpacesDrawerPage { $(userMenuContainer(Space.treasury)).$(userSectionHeader(Space.treasury)), findsOneWidget, ); - final children = find.descendant( - of: $(userMenuContainer(Space.treasury)), - matching: $(userDrawerMenuItem), + expect( + $(userMenuContainer(Space.treasury)).$(userDrawerMenuItem), + findsAtLeast(1), ); - expect($(children), findsAtLeast(1)); } static void userVotingLooksAsExpected(PatrolTester $) { @@ -132,11 +131,10 @@ class SpacesDrawerPage { $(userMenuContainer(Space.voting)).$(userSectionHeader(Space.voting)), findsOneWidget, ); - final children = find.descendant( - of: $(userMenuContainer(Space.voting)), - matching: $(userDrawerMenuItem), + expect( + $(userMenuContainer(Space.voting)).$(userDrawerMenuItem), + findsAtLeast(1), ); - expect($(children), findsAtLeast(1)); } static void userWorkspaceLooksAsExpected(PatrolTester $) { @@ -149,10 +147,5 @@ class SpacesDrawerPage { .$(userSectionHeader(Space.workspace)), findsOneWidget, ); - final children = find.descendant( - of: $(userMenuContainer(Space.workspace)), - matching: $(userDrawerMenuItem), - ); - expect($(children), findsAtLeast(1)); } } diff --git a/catalyst_voices/apps/voices/integration_test/suites/account_test.dart b/catalyst_voices/apps/voices/integration_test/suites/account_test.dart index 6bae0391148..3ebf83182d4 100644 --- a/catalyst_voices/apps/voices/integration_test/suites/account_test.dart +++ b/catalyst_voices/apps/voices/integration_test/suites/account_test.dart @@ -9,6 +9,7 @@ import 'package:patrol_finders/patrol_finders.dart'; import '../pageobject/account_dropdown_page.dart'; import '../pageobject/app_bar_page.dart'; import '../pageobject/overall_spaces_page.dart'; +import '../utils/constants.dart'; void main() async { late final GoRouter router; @@ -34,7 +35,7 @@ void main() async { (PatrolTester $) async { await $.pumpWidgetAndSettle(App(routerConfig: router)); await $(OverallSpacesPage.userShortcutBtn) - .tap(settleTimeout: const Duration(seconds: 10)); + .tap(settleTimeout: Time.long.duration); await $(AppBarPage.accountPopupBtn).tap(); await AccountDropdownPage.accountDropdownLooksAsExpected($); await AccountDropdownPage.accountDropdownContainsSpecificData($); diff --git a/catalyst_voices/apps/voices/integration_test/suites/app_test.dart b/catalyst_voices/apps/voices/integration_test/suites/app_test.dart index 11d0f9a6d30..b52e4d56bf3 100644 --- a/catalyst_voices/apps/voices/integration_test/suites/app_test.dart +++ b/catalyst_voices/apps/voices/integration_test/suites/app_test.dart @@ -10,6 +10,7 @@ import 'package:patrol_finders/patrol_finders.dart'; import '../pageobject/app_bar_page.dart'; import '../pageobject/overall_spaces_page.dart'; import '../pageobject/spaces_drawer_page.dart'; +import '../utils/constants.dart'; import '../utils/selector_utils.dart'; void main() async { @@ -34,7 +35,7 @@ void main() async { (PatrolTester $) async { await $.pumpWidgetAndSettle(App(routerConfig: router)); await $(OverallSpacesPage.visitorShortcutBtn) - .tap(settleTimeout: const Duration(seconds: 10)); + .tap(settleTimeout: Time.long.duration); expect($(AppBarPage.spacesDrawerButton).exists, false); }, ); @@ -46,7 +47,7 @@ void main() async { (PatrolTester $) async { await $.pumpWidgetAndSettle(App(routerConfig: router)); await $(OverallSpacesPage.guestShortcutBtn) - .tap(settleTimeout: const Duration(seconds: 10)); + .tap(settleTimeout: Time.long.duration); await $(AppBarPage.spacesDrawerButton).waitUntilVisible().tap(); SpacesDrawerPage.commonElementsLookAsExpected($); @@ -66,7 +67,7 @@ void main() async { (PatrolTester $) async { await $.pumpWidgetAndSettle(App(routerConfig: router)); await $(OverallSpacesPage.guestShortcutBtn) - .tap(settleTimeout: const Duration(seconds: 10)); + .tap(settleTimeout: Time.long.duration); await $(AppBarPage.spacesDrawerButton).waitUntilVisible().tap(); // iterate thru spaces by clicking next @@ -92,7 +93,7 @@ void main() async { (PatrolTester $) async { await $.pumpWidgetAndSettle(App(routerConfig: router)); await $(OverallSpacesPage.userShortcutBtn) - .tap(settleTimeout: const Duration(seconds: 10)); + .tap(settleTimeout: Time.long.duration); await $(AppBarPage.spacesDrawerButton).waitUntilVisible().tap(); SpacesDrawerPage.commonElementsLookAsExpected($); for (final space in Space.values) { @@ -107,7 +108,7 @@ void main() async { (PatrolTester $) async { await $.pumpWidgetAndSettle(App(routerConfig: router)); await $(OverallSpacesPage.guestShortcutBtn) - .tap(settleTimeout: const Duration(seconds: 10)); + .tap(settleTimeout: Time.long.duration); await $(AppBarPage.spacesDrawerButton).waitUntilVisible().tap(); await $(SpacesDrawerPage.allSpacesBtn).tap(); expect($(OverallSpacesPage.spacesListView), findsOneWidget); @@ -119,7 +120,7 @@ void main() async { (PatrolTester $) async { await $.pumpWidgetAndSettle(App(routerConfig: router)); await $(OverallSpacesPage.userShortcutBtn) - .tap(settleTimeout: const Duration(seconds: 10)); + .tap(settleTimeout: Time.long.duration); await $(AppBarPage.spacesDrawerButton).waitUntilVisible().tap(); await $(SpacesDrawerPage.allSpacesBtn).tap(); expect($(OverallSpacesPage.spacesListView), findsOneWidget); @@ -138,7 +139,7 @@ void main() async { }; await $.pumpWidgetAndSettle(App(routerConfig: router)); await $(OverallSpacesPage.userShortcutBtn) - .tap(settleTimeout: const Duration(seconds: 10)); + .tap(settleTimeout: Time.long.duration); await $(AppBarPage.spacesDrawerButton).waitUntilVisible().tap(); for (final space in Space.values) { await $(SpacesDrawerPage.chooserItem(space)).tap(); diff --git a/catalyst_voices/apps/voices/integration_test/suites/onboarding_test.dart b/catalyst_voices/apps/voices/integration_test/suites/onboarding_test.dart index 3a520bc4664..62d832c33cc 100644 --- a/catalyst_voices/apps/voices/integration_test/suites/onboarding_test.dart +++ b/catalyst_voices/apps/voices/integration_test/suites/onboarding_test.dart @@ -9,7 +9,11 @@ import 'package:patrol_finders/patrol_finders.dart'; import '../pageobject/app_bar_page.dart'; import '../pageobject/onboarding_page.dart'; import '../pageobject/overall_spaces_page.dart'; +import '../types/password_validation_states.dart'; import '../types/registration_state.dart'; +import '../utils/constants.dart'; +import '../utils/test_context.dart'; +import '../utils/translations_utils.dart'; void main() async { late final GoRouter router; @@ -25,6 +29,7 @@ void main() async { tearDown(() async { await restartDependencies(); + TestContext.clearContext(); }); group( @@ -35,7 +40,7 @@ void main() async { (PatrolTester $) async { await $.pumpWidgetAndSettle(App(routerConfig: router)); await $(OverallSpacesPage.visitorShortcutBtn) - .tap(settleTimeout: const Duration(seconds: 10)); + .tap(settleTimeout: Time.long.duration); await $(AppBarPage.getStartedBtn).tap(); expect($(OnboardingPage.registrationInfoPanel), findsOneWidget); expect($(OnboardingPage.registrationDetailsPanel), findsOneWidget); @@ -47,7 +52,7 @@ void main() async { (PatrolTester $) async { await $.pumpWidgetAndSettle(App(routerConfig: router)); await $(AppBarPage.getStartedBtn) - .tap(settleTimeout: const Duration(seconds: 10)); + .tap(settleTimeout: Time.long.duration); await OnboardingPage.onboardingScreenLooksAsExpected( $, RegistrationState.getStarted, @@ -60,7 +65,7 @@ void main() async { (PatrolTester $) async { await $.pumpWidgetAndSettle(App(routerConfig: router)); await $(AppBarPage.getStartedBtn) - .tap(settleTimeout: const Duration(seconds: 10)); + .tap(settleTimeout: Time.long.duration); await OnboardingPage.closeBtn($).tap(); expect($(OnboardingPage.registrationDialog), findsNothing); }, @@ -71,7 +76,7 @@ void main() async { (PatrolTester $) async { await $.pumpWidgetAndSettle(App(routerConfig: router)); await $(AppBarPage.getStartedBtn) - .tap(settleTimeout: const Duration(seconds: 10)); + .tap(settleTimeout: Time.long.duration); await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); await OnboardingPage.onboardingScreenLooksAsExpected( $, @@ -85,7 +90,7 @@ void main() async { (PatrolTester $) async { await $.pumpWidgetAndSettle(App(routerConfig: router)); await $(AppBarPage.getStartedBtn) - .tap(settleTimeout: const Duration(seconds: 10)); + .tap(settleTimeout: Time.long.duration); await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); await ($(OnboardingPage.backButton)).waitUntilVisible().tap(); await OnboardingPage.registrationInfoPanelLooksAsExpected( @@ -100,12 +105,12 @@ void main() async { (PatrolTester $) async { await $.pumpWidgetAndSettle(App(routerConfig: router)); await $(AppBarPage.getStartedBtn) - .tap(settleTimeout: const Duration(seconds: 10)); + .tap(settleTimeout: Time.long.duration); await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); await OnboardingPage.onboardingScreenLooksAsExpected( $, - RegistrationState.createKeychainInfo, + RegistrationState.keychainCreated, ); }, ); @@ -115,7 +120,7 @@ void main() async { (PatrolTester $) async { await $.pumpWidgetAndSettle(App(routerConfig: router)); await $(AppBarPage.getStartedBtn) - .tap(settleTimeout: const Duration(seconds: 10)); + .tap(settleTimeout: Time.long.duration); await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); await ($(OnboardingPage.backButton)).waitUntilVisible().tap(); @@ -130,7 +135,7 @@ void main() async { (PatrolTester $) async { await $.pumpWidgetAndSettle(App(routerConfig: router)); await $(AppBarPage.getStartedBtn) - .tap(settleTimeout: const Duration(seconds: 10)); + .tap(settleTimeout: Time.long.duration); await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); await $(OnboardingPage.nextButton).tap(); @@ -145,7 +150,7 @@ void main() async { (PatrolTester $) async { await $.pumpWidgetAndSettle(App(routerConfig: router)); await $(AppBarPage.getStartedBtn) - .tap(settleTimeout: const Duration(seconds: 10)); + .tap(settleTimeout: Time.long.duration); await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); await $(OnboardingPage.nextButton).tap(); @@ -162,7 +167,7 @@ void main() async { (PatrolTester $) async { await $.pumpWidgetAndSettle(App(routerConfig: router)); await $(AppBarPage.getStartedBtn) - .tap(settleTimeout: const Duration(seconds: 10)); + .tap(settleTimeout: Time.long.duration); await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); await $(OnboardingPage.nextButton).tap(); @@ -170,10 +175,7 @@ void main() async { $, RegistrationState.keychainCreateMnemonicWritedown, ); - OnboardingPage.voicesFilledButtonIsDisabled( - $, - OnboardingPage.nextButton, - ); + OnboardingPage.voicesButtonIsDisabled($, OnboardingPage.nextButton); }, ); @@ -182,7 +184,7 @@ void main() async { (PatrolTester $) async { await $.pumpWidgetAndSettle(App(routerConfig: router)); await $(AppBarPage.getStartedBtn) - .tap(settleTimeout: const Duration(seconds: 10)); + .tap(settleTimeout: Time.long.duration); await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); await $(OnboardingPage.nextButton).tap(); @@ -200,7 +202,7 @@ void main() async { (PatrolTester $) async { await $.pumpWidgetAndSettle(App(routerConfig: router)); await $(AppBarPage.getStartedBtn) - .tap(settleTimeout: const Duration(seconds: 10)); + .tap(settleTimeout: Time.long.duration); await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); await $(OnboardingPage.nextButton).tap(); @@ -219,7 +221,7 @@ void main() async { (PatrolTester $) async { await $.pumpWidgetAndSettle(App(routerConfig: router)); await $(AppBarPage.getStartedBtn) - .tap(settleTimeout: const Duration(seconds: 10)); + .tap(settleTimeout: Time.long.duration); await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); await $(OnboardingPage.nextButton).tap(); @@ -227,6 +229,7 @@ void main() async { await $(OnboardingPage.nextButton).tap(); await $(OnboardingPage.nextButton).tap(); //temporary: remove reset when seeds are no longer prefilled + //https://github.com/input-output-hk/catalyst-voices/issues/1531 await $(OnboardingPage.resetButton).tap(); await OnboardingPage.onboardingScreenLooksAsExpected( $, @@ -240,13 +243,86 @@ void main() async { (PatrolTester $) async { await $.pumpWidgetAndSettle(App(routerConfig: router)); await $(AppBarPage.getStartedBtn) - .tap(settleTimeout: const Duration(seconds: 10)); + .tap(settleTimeout: Time.long.duration); + await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); + await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.seedPhraseStoredCheckbox).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await ($(OnboardingPage.backButton)).waitUntilVisible().tap(); + await OnboardingPage.registrationInfoPanelLooksAsExpected( + $, + RegistrationState.keychainCreateMnemonicInputInfo, + ); + }, + ); + + patrolWidgetTest( + 'visitor - create - mnemonic input - correct words unlock next button', + (PatrolTester $) async { + await $.pumpWidgetAndSettle(App(routerConfig: router)); + await $(AppBarPage.getStartedBtn) + .tap(settleTimeout: Time.long.duration); + await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); + await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.storeSeedPhrases($); + await $(OnboardingPage.seedPhraseStoredCheckbox).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + //temporary: remove reset when seeds are no longer prefilled + //https://github.com/input-output-hk/catalyst-voices/issues/1531//temporary: remove reset when seeds are no longer prefilled + //https://github.com/input-output-hk/catalyst-voices/issues/1531 + await $(OnboardingPage.resetButton).tap(); + await OnboardingPage.enterStoredSeedPhrases($); + OnboardingPage.voicesButtonIsEnabled($, OnboardingPage.nextButton); + }, + ); + + patrolWidgetTest( + 'visitor - create - mnemonic input verified screen looks OK', + (PatrolTester $) async { + await $.pumpWidgetAndSettle(App(routerConfig: router)); + await $(AppBarPage.getStartedBtn) + .tap(settleTimeout: Time.long.duration); + await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); + await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.storeSeedPhrases($); + await $(OnboardingPage.seedPhraseStoredCheckbox).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + //temporary: remove reset when seeds are no longer prefilled + //https://github.com/input-output-hk/catalyst-voices/issues/1531 + await $(OnboardingPage.resetButton).tap(); + await OnboardingPage.enterStoredSeedPhrases($); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.onboardingScreenLooksAsExpected( + $, + RegistrationState.keychainCreateMnemonicVerified, + ); + }, + ); + + patrolWidgetTest( + 'visitor - create - mnemonic input verified screen back button works', + (PatrolTester $) async { + await $.pumpWidgetAndSettle(App(routerConfig: router)); + await $(AppBarPage.getStartedBtn) + .tap(settleTimeout: Time.long.duration); await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.storeSeedPhrases($); await $(OnboardingPage.seedPhraseStoredCheckbox).tap(); await $(OnboardingPage.nextButton).tap(); await $(OnboardingPage.nextButton).tap(); + //temporary: remove reset when seeds are no longer prefilled + //https://github.com/input-output-hk/catalyst-voices/issues/1531 + await $(OnboardingPage.resetButton).tap(); + await OnboardingPage.enterStoredSeedPhrases($); + await $(OnboardingPage.nextButton).tap(); await ($(OnboardingPage.backButton)).waitUntilVisible().tap(); await OnboardingPage.registrationInfoPanelLooksAsExpected( $, @@ -254,6 +330,453 @@ void main() async { ); }, ); + + patrolWidgetTest( + 'visitor - create - password info screen looks OK', + (PatrolTester $) async { + await $.pumpWidgetAndSettle(App(routerConfig: router)); + await $(AppBarPage.getStartedBtn) + .tap(settleTimeout: Time.long.duration); + await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); + await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.storeSeedPhrases($); + await $(OnboardingPage.seedPhraseStoredCheckbox).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + //temporary: remove reset when seeds are no longer prefilled + //https://github.com/input-output-hk/catalyst-voices/issues/1531 + await $(OnboardingPage.resetButton).tap(); + await OnboardingPage.enterStoredSeedPhrases($); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.onboardingScreenLooksAsExpected( + $, + RegistrationState.passwordInfo, + ); + }, + ); + + patrolWidgetTest( + 'visitor - create - password info screen back button works', + (PatrolTester $) async { + await $.pumpWidgetAndSettle(App(routerConfig: router)); + await $(AppBarPage.getStartedBtn) + .tap(settleTimeout: Time.long.duration); + await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); + await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.storeSeedPhrases($); + await $(OnboardingPage.seedPhraseStoredCheckbox).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + //temporary: remove reset when seeds are no longer prefilled + //https://github.com/input-output-hk/catalyst-voices/issues/1531 + await $(OnboardingPage.resetButton).tap(); + await OnboardingPage.enterStoredSeedPhrases($); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await ($(OnboardingPage.backButton)).waitUntilVisible().tap(); + expect( + $(OnboardingPage.nextStepBody).text, + T.get('Now let’s set your Unlock password ' + 'for this device!'), + ); + }, + ); + + patrolWidgetTest( + 'visitor - create - password input screen looks OK', + (PatrolTester $) async { + await $.pumpWidgetAndSettle(App(routerConfig: router)); + await $(AppBarPage.getStartedBtn) + .tap(settleTimeout: Time.long.duration); + await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); + await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.storeSeedPhrases($); + await $(OnboardingPage.seedPhraseStoredCheckbox).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + //temporary: remove reset when seeds are no longer prefilled + //https://github.com/input-output-hk/catalyst-voices/issues/1531 + await $(OnboardingPage.resetButton).tap(); + await OnboardingPage.enterStoredSeedPhrases($); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.onboardingScreenLooksAsExpected( + $, + RegistrationState.passwordInput, + ); + }, + ); + + patrolWidgetTest( + 'visitor - create - password input screen back button works', + (PatrolTester $) async { + await $.pumpWidgetAndSettle(App(routerConfig: router)); + await $(AppBarPage.getStartedBtn) + .tap(settleTimeout: Time.long.duration); + await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); + await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.storeSeedPhrases($); + await $(OnboardingPage.seedPhraseStoredCheckbox).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + //temporary: remove reset when seeds are no longer prefilled + //https://github.com/input-output-hk/catalyst-voices/issues/1531 + await $(OnboardingPage.resetButton).tap(); + await OnboardingPage.enterStoredSeedPhrases($); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await ($(OnboardingPage.backButton)).waitUntilVisible().tap(); + await OnboardingPage.registrationDetailsPanelLooksAsExpected( + $, + RegistrationState.passwordInfo, + ); + }, + ); + + patrolWidgetTest( + 'visitor - create - password input - valid minimum length password', + (PatrolTester $) async { + await $.pumpWidgetAndSettle(App(routerConfig: router)); + await $(AppBarPage.getStartedBtn) + .tap(settleTimeout: Time.long.duration); + await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); + await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.storeSeedPhrases($); + await $(OnboardingPage.seedPhraseStoredCheckbox).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + //temporary: remove reset when seeds are no longer prefilled + //https://github.com/input-output-hk/catalyst-voices/issues/1531 + await $(OnboardingPage.resetButton).tap(); + await OnboardingPage.enterStoredSeedPhrases($); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.enterPassword($, 'Test1234'); + await OnboardingPage.enterPasswordConfirm($, 'Test1234'); + OnboardingPage.passwordConfirmErrorIconIsShown( + $, + reverse: true, + ); + OnboardingPage.checkValidationIndicator( + $, + PasswordValidationStatus.normal, + ); + OnboardingPage.passwordConfirmErrorIconIsShown( + $, + reverse: true, + ); + OnboardingPage.voicesButtonIsEnabled($, OnboardingPage.nextButton); + }, + ); + + patrolWidgetTest( + 'visitor - create - password input - valid long password', + (PatrolTester $) async { + await $.pumpWidgetAndSettle(App(routerConfig: router)); + await $(AppBarPage.getStartedBtn) + .tap(settleTimeout: Time.long.duration); + await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); + await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.storeSeedPhrases($); + await $(OnboardingPage.seedPhraseStoredCheckbox).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + //temporary: remove reset when seeds are no longer prefilled + //https://github.com/input-output-hk/catalyst-voices/issues/1531 + await $(OnboardingPage.resetButton).tap(); + await OnboardingPage.enterStoredSeedPhrases($); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.enterPassword($, 'Test1234Test1234'); + await OnboardingPage.enterPasswordConfirm($, 'Test1234Test1234'); + OnboardingPage.checkValidationIndicator( + $, + PasswordValidationStatus.good, + ); + OnboardingPage.passwordConfirmErrorIconIsShown( + $, + reverse: true, + ); + OnboardingPage.voicesButtonIsEnabled($, OnboardingPage.nextButton); + }, + ); + + patrolWidgetTest( + 'visitor - create - password input - too short password', + (PatrolTester $) async { + await $.pumpWidgetAndSettle(App(routerConfig: router)); + await $(AppBarPage.getStartedBtn) + .tap(settleTimeout: Time.long.duration); + await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); + await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.storeSeedPhrases($); + await $(OnboardingPage.seedPhraseStoredCheckbox).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + //temporary: remove reset when seeds are no longer prefilled + //https://github.com/input-output-hk/catalyst-voices/issues/1531 + await $(OnboardingPage.resetButton).tap(); + await OnboardingPage.enterStoredSeedPhrases($); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.enterPassword($, 'Test123'); + OnboardingPage.checkValidationIndicator( + $, + PasswordValidationStatus.weak, + ); + OnboardingPage.passwordConfirmErrorIconIsShown( + $, + reverse: true, + ); + OnboardingPage.voicesButtonIsDisabled($, OnboardingPage.nextButton); + }, + ); + + patrolWidgetTest( + 'visitor - create - password input - valid password, no confirmation', + (PatrolTester $) async { + await $.pumpWidgetAndSettle(App(routerConfig: router)); + await $(AppBarPage.getStartedBtn) + .tap(settleTimeout: Time.long.duration); + await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); + await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.storeSeedPhrases($); + await $(OnboardingPage.seedPhraseStoredCheckbox).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + //temporary: remove reset when seeds are no longer prefilled + //https://github.com/input-output-hk/catalyst-voices/issues/1531 + await $(OnboardingPage.resetButton).tap(); + await OnboardingPage.enterStoredSeedPhrases($); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.enterPassword($, 'Test1234'); + OnboardingPage.checkValidationIndicator( + $, + PasswordValidationStatus.normal, + ); + OnboardingPage.passwordConfirmErrorIconIsShown( + $, + reverse: true, + ); + OnboardingPage.voicesButtonIsDisabled($, OnboardingPage.nextButton); + }, + ); + + patrolWidgetTest( + 'visitor - create - password input - not matching confirmation', + (PatrolTester $) async { + await $.pumpWidgetAndSettle(App(routerConfig: router)); + await $(AppBarPage.getStartedBtn) + .tap(settleTimeout: Time.long.duration); + await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); + await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.storeSeedPhrases($); + await $(OnboardingPage.seedPhraseStoredCheckbox).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + //temporary: remove reset when seeds are no longer prefilled + //https://github.com/input-output-hk/catalyst-voices/issues/1531 + await $(OnboardingPage.resetButton).tap(); + await OnboardingPage.enterStoredSeedPhrases($); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.enterPassword($, 'Test1234'); + await OnboardingPage.enterPasswordConfirm($, 'Test123'); + OnboardingPage.checkValidationIndicator( + $, + PasswordValidationStatus.normal, + ); + OnboardingPage.passwordConfirmErrorIconIsShown($); + OnboardingPage.voicesButtonIsDisabled($, OnboardingPage.nextButton); + }, + ); + + patrolWidgetTest( + 'visitor - create - keychain created success screen looks OK', + (PatrolTester $) async { + await $.pumpWidgetAndSettle(App(routerConfig: router)); + await $(AppBarPage.getStartedBtn) + .tap(settleTimeout: Time.long.duration); + await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); + await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.storeSeedPhrases($); + await $(OnboardingPage.seedPhraseStoredCheckbox).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + //temporary: remove reset when seeds are no longer prefilled + //https://github.com/input-output-hk/catalyst-voices/issues/1531 + await $(OnboardingPage.resetButton).tap(); + await OnboardingPage.enterStoredSeedPhrases($); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.enterPassword($, 'Test1234'); + await OnboardingPage.enterPasswordConfirm($, 'Test1234'); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.onboardingScreenLooksAsExpected( + $, + RegistrationState.keychainCreateSuccess, + ); + }, + ); + + patrolWidgetTest( + 'visitor - create - link wallet info screen looks OK', + (PatrolTester $) async { + await $.pumpWidgetAndSettle(App(routerConfig: router)); + await $(AppBarPage.getStartedBtn) + .tap(settleTimeout: Time.long.duration); + await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); + await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.storeSeedPhrases($); + await $(OnboardingPage.seedPhraseStoredCheckbox).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + //temporary: remove reset when seeds are no longer prefilled + //https://github.com/input-output-hk/catalyst-voices/issues/1531 + await $(OnboardingPage.resetButton).tap(); + await OnboardingPage.enterStoredSeedPhrases($); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.enterPassword($, 'Test1234'); + await OnboardingPage.enterPasswordConfirm($, 'Test1234'); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.linkWalletAndRolesButton).tap(); + await OnboardingPage.onboardingScreenLooksAsExpected( + $, + RegistrationState.linkWalletInfo, + ); + }, + ); + + patrolWidgetTest( + 'visitor - create - link wallet select screen looks OK', + (PatrolTester $) async { + await $.pumpWidgetAndSettle(App(routerConfig: router)); + await $(AppBarPage.getStartedBtn) + .tap(settleTimeout: Time.long.duration); + await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); + await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.storeSeedPhrases($); + await $(OnboardingPage.seedPhraseStoredCheckbox).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + //temporary: remove reset when seeds are no longer prefilled + //https://github.com/input-output-hk/catalyst-voices/issues/1531 + await $(OnboardingPage.resetButton).tap(); + await OnboardingPage.enterStoredSeedPhrases($); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.enterPassword($, 'Test1234'); + await OnboardingPage.enterPasswordConfirm($, 'Test1234'); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.linkWalletAndRolesButton).tap(); + await $(OnboardingPage.chooseCardanoWalletButton).tap(); + await OnboardingPage.onboardingScreenLooksAsExpected( + $, + RegistrationState.linkWalletSelect, + ); + }, + ); + + patrolWidgetTest( + 'visitor - create - link wallet select screen back button works', + (PatrolTester $) async { + await $.pumpWidgetAndSettle(App(routerConfig: router)); + await $(AppBarPage.getStartedBtn) + .tap(settleTimeout: Time.long.duration); + await OnboardingPage.detailsPartGetStartedCreateNewBtn($).tap(); + await OnboardingPage.detailsPartCreateKeychainBtn($).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.storeSeedPhrases($); + await $(OnboardingPage.seedPhraseStoredCheckbox).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + //temporary: remove reset when seeds are no longer prefilled + //https://github.com/input-output-hk/catalyst-voices/issues/1531 + await $(OnboardingPage.resetButton).tap(); + await OnboardingPage.enterStoredSeedPhrases($); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.nextButton).tap(); + await OnboardingPage.enterPassword($, 'Test1234'); + await OnboardingPage.enterPasswordConfirm($, 'Test1234'); + await $(OnboardingPage.nextButton).tap(); + await $(OnboardingPage.linkWalletAndRolesButton).tap(); + await $(OnboardingPage.chooseCardanoWalletButton).tap(); + await ($(OnboardingPage.backButton)).waitUntilVisible().tap(); + await OnboardingPage.onboardingScreenLooksAsExpected( + $, + RegistrationState.linkWalletInfo, + ); + }, + ); + + patrolWidgetTest( + 'visitor - restore - keychain choice screen looks OK', + (PatrolTester $) async { + await $.pumpWidgetAndSettle(App(routerConfig: router)); + await $(AppBarPage.getStartedBtn) + .tap(settleTimeout: Time.long.duration); + await OnboardingPage.detailsPartGetStartedRecoverBtn($).tap(); + await OnboardingPage.onboardingScreenLooksAsExpected( + $, + RegistrationState.keychainRestoreChoice, + ); + }, + ); + + patrolWidgetTest( + 'visitor - restore - keychain choice screen back button works', + (PatrolTester $) async { + await $.pumpWidgetAndSettle(App(routerConfig: router)); + await $(AppBarPage.getStartedBtn) + .tap(settleTimeout: Time.long.duration); + await OnboardingPage.detailsPartGetStartedRecoverBtn($).tap(); + await ($(OnboardingPage.backButton)).waitUntilVisible().tap(); + await OnboardingPage.onboardingScreenLooksAsExpected( + $, + RegistrationState.getStarted, + ); + }, + ); + }, + skip: true, + ); + + patrolWidgetTest( + 'visitor - restore - keychain choice screen looks OK', + (PatrolTester $) async { + await $.pumpWidgetAndSettle(App(routerConfig: router)); + await $(AppBarPage.getStartedBtn).tap(settleTimeout: Time.long.duration); + await OnboardingPage.detailsPartGetStartedRecoverBtn($).tap(); + await OnboardingPage.onboardingScreenLooksAsExpected( + $, + RegistrationState.keychainRestoreChoice, + ); }, ); } diff --git a/catalyst_voices/apps/voices/integration_test/types/password_validation_states.dart b/catalyst_voices/apps/voices/integration_test/types/password_validation_states.dart new file mode 100644 index 00000000000..a0ee5e6297b --- /dev/null +++ b/catalyst_voices/apps/voices/integration_test/types/password_validation_states.dart @@ -0,0 +1,5 @@ +enum PasswordValidationStatus { + weak, + normal, + good; +} diff --git a/catalyst_voices/apps/voices/integration_test/utils/constants.dart b/catalyst_voices/apps/voices/integration_test/utils/constants.dart new file mode 100644 index 00000000000..b03074474cd --- /dev/null +++ b/catalyst_voices/apps/voices/integration_test/utils/constants.dart @@ -0,0 +1,9 @@ +enum Time { + veryShort(Duration(milliseconds: 500)), + short(Duration(seconds: 2)), + long(Duration(minutes: 10)); + + final Duration duration; + + const Time(this.duration); +} diff --git a/catalyst_voices/apps/voices/integration_test/utils/selector_utils.dart b/catalyst_voices/apps/voices/integration_test/utils/selector_utils.dart index 67a0c980078..9ab6c5b57e6 100644 --- a/catalyst_voices/apps/voices/integration_test/utils/selector_utils.dart +++ b/catalyst_voices/apps/voices/integration_test/utils/selector_utils.dart @@ -7,11 +7,11 @@ class SelectorUtils { PatrolFinder widget, { bool? reverse = false, }) { - final widgetProps = $.tester.widget(widget).toString().split('(').last; + final dynamic widgetProps = $.tester.widget(widget); final expectedState = reverse! ? 'enabled' : 'disabled'; expect( - widgetProps.contains('disabled'), - !reverse, + widgetProps.enabled, // ignore: avoid_dynamic_calls + reverse, reason: 'Expected $expectedState (${widget.description})', ); } diff --git a/catalyst_voices/apps/voices/integration_test/utils/test_context.dart b/catalyst_voices/apps/voices/integration_test/utils/test_context.dart new file mode 100644 index 00000000000..b3c951aecac --- /dev/null +++ b/catalyst_voices/apps/voices/integration_test/utils/test_context.dart @@ -0,0 +1,42 @@ +class TestContext { + TestContext._privateConstructor(); + static final TestContext instance = TestContext._privateConstructor(); + Map context = {}; + + static bool has({required String key}) { + return TestContext.instance.context.containsKey(key); + } + + static void save({required String key, required String value}) { + if (has(key: key)) { + throw Exception('You tried to override "$key" property. Its not allowed'); + } + TestContext.instance.context[key] = value; + } + + static void delete({required String key}) { + if (has(key: key)) { + TestContext.instance.context.remove(key); + } + } + + static void saveWithOverride({required String key, required String value}) { + if (has(key: key)) { + delete(key: key); + } + TestContext.instance.context[key] = value; + } + + static String get({required String key}) { + if (has(key: key)) { + return TestContext.instance.context[key]!; + } + throw Exception( + 'You tried to access $key property, but it does not exist.', + ); + } + + static void clearContext() { + TestContext.instance.context.clear(); + } +} diff --git a/catalyst_voices/apps/voices/lib/pages/registration/finish_account/finish_account_creation_panel.dart b/catalyst_voices/apps/voices/lib/pages/registration/finish_account/finish_account_creation_panel.dart index 137d69cb600..9e2c3140b1c 100644 --- a/catalyst_voices/apps/voices/lib/pages/registration/finish_account/finish_account_creation_panel.dart +++ b/catalyst_voices/apps/voices/lib/pages/registration/finish_account/finish_account_creation_panel.dart @@ -13,6 +13,7 @@ class FinishAccountCreationPanel extends StatelessWidget { @override Widget build(BuildContext context) { return Column( + key: const Key('FinishAccountCreationPanel'), crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const SizedBox(height: 24), @@ -78,6 +79,7 @@ class _LinkWalletAndRolesButton extends StatelessWidget { @override Widget build(BuildContext context) { return VoicesFilledButton( + key: const Key('LinkWalletAndRolesButton'), onTap: onTap, leading: VoicesAssets.icons.wallet.buildIcon(size: 18), child: Text(context.l10n.createKeychainLinkWalletAndRoles), diff --git a/catalyst_voices/apps/voices/lib/pages/registration/recover/recover_method_panel.dart b/catalyst_voices/apps/voices/lib/pages/registration/recover/recover_method_panel.dart index eb6b9c49d0c..93697d74aba 100644 --- a/catalyst_voices/apps/voices/lib/pages/registration/recover/recover_method_panel.dart +++ b/catalyst_voices/apps/voices/lib/pages/registration/recover/recover_method_panel.dart @@ -24,6 +24,7 @@ class RecoverMethodPanel extends StatelessWidget { children: [ const SizedBox(height: 24), Text( + key: const Key('RecoverKeychainMethodsTitle'), context.l10n.recoverKeychainMethodsTitle, style: theme.textTheme.titleMedium?.copyWith(color: colorLvl1), ), @@ -31,11 +32,13 @@ class RecoverMethodPanel extends StatelessWidget { _BlocOnDeviceKeychains(onUnlockTap: _unlockKeychain), const SizedBox(height: 12), Text( + key: const Key('RecoverKeychainMethodsSubtitle'), context.l10n.recoverKeychainMethodsSubtitle, style: theme.textTheme.bodyMedium?.copyWith(color: colorLvl1), ), const SizedBox(height: 32), Text( + key: const Key('RecoverKeychainMethodsListTitle'), context.l10n.recoverKeychainMethodsListTitle, style: theme.textTheme.titleSmall?.copyWith(color: colorLvl0), ), @@ -89,6 +92,7 @@ class _BlocOnDeviceKeychains extends StatelessWidget { @override Widget build(BuildContext context) { return BlocRecoverBuilder( + key: const Key('BlocOnDeviceKeychains'), selector: (state) => state.foundKeychain, builder: (context, state) { return _OnDeviceKeychains( @@ -151,6 +155,7 @@ class _KeychainNotFoundIndicator extends StatelessWidget { @override Widget build(BuildContext context) { return VoicesIndicator( + key: const Key('KeychainNotFoundIndicator'), type: VoicesIndicatorType.error, icon: VoicesAssets.icons.exclamation, message: Text( diff --git a/catalyst_voices/apps/voices/lib/pages/registration/wallet_link/stage/intro_panel.dart b/catalyst_voices/apps/voices/lib/pages/registration/wallet_link/stage/intro_panel.dart index 7a1de2efca9..512fe5f4b80 100644 --- a/catalyst_voices/apps/voices/lib/pages/registration/wallet_link/stage/intro_panel.dart +++ b/catalyst_voices/apps/voices/lib/pages/registration/wallet_link/stage/intro_panel.dart @@ -20,6 +20,7 @@ class IntroPanel extends StatelessWidget { ), const Spacer(), VoicesFilledButton( + key: const Key('ChooseCardanoWalletButton'), leading: VoicesAssets.icons.wallet.buildIcon(), onTap: () { RegistrationCubit.of(context).nextStep(); diff --git a/catalyst_voices/apps/voices/lib/pages/registration/wallet_link/stage/select_wallet_panel.dart b/catalyst_voices/apps/voices/lib/pages/registration/wallet_link/stage/select_wallet_panel.dart index 0a962b81d54..d4520daab78 100644 --- a/catalyst_voices/apps/voices/lib/pages/registration/wallet_link/stage/select_wallet_panel.dart +++ b/catalyst_voices/apps/voices/lib/pages/registration/wallet_link/stage/select_wallet_panel.dart @@ -60,6 +60,7 @@ class _SelectWalletPanelState extends State { ), const SizedBox(height: 10), VoicesTextButton( + key: const Key('SeeAllSupportedWalletsButton'), trailing: VoicesAssets.icons.externalLink.buildIcon(), onTap: () async => _launchSupportedWalletsLink(), child: Text(context.l10n.seeAllSupportedWallets), @@ -101,6 +102,7 @@ class _BlocWallets extends StatelessWidget { @override Widget build(BuildContext context) { return BlocWalletLinkBuilder, Exception>?>( + key: const Key('WalletsLinkBuilder'), selector: (state) => state.wallets, builder: (context, state) { return _Wallets( diff --git a/catalyst_voices/apps/voices/lib/pages/registration/widgets/next_step.dart b/catalyst_voices/apps/voices/lib/pages/registration/widgets/next_step.dart index ce7bec1065c..7f2309cab32 100644 --- a/catalyst_voices/apps/voices/lib/pages/registration/widgets/next_step.dart +++ b/catalyst_voices/apps/voices/lib/pages/registration/widgets/next_step.dart @@ -25,6 +25,7 @@ class NextStep extends StatelessWidget { const SizedBox(height: 12), if (data != null) ...[ Text( + key: const Key('NextStepBody'), data, style: theme.textTheme.bodySmall?.copyWith(color: textColor), textAlign: TextAlign.center, diff --git a/catalyst_voices/apps/voices/lib/pages/registration/widgets/registration_tile.dart b/catalyst_voices/apps/voices/lib/pages/registration/widgets/registration_tile.dart index 0db8b0ed560..dca3b9d14a6 100644 --- a/catalyst_voices/apps/voices/lib/pages/registration/widgets/registration_tile.dart +++ b/catalyst_voices/apps/voices/lib/pages/registration/widgets/registration_tile.dart @@ -47,6 +47,7 @@ class RegistrationTile extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ Text( + key: const Key('RegistrationTileTitle'), title, maxLines: 2, overflow: TextOverflow.ellipsis, diff --git a/catalyst_voices/apps/voices/lib/pages/registration/widgets/unlock_password_form.dart b/catalyst_voices/apps/voices/lib/pages/registration/widgets/unlock_password_form.dart index 54bbf18a171..5fb20445671 100644 --- a/catalyst_voices/apps/voices/lib/pages/registration/widgets/unlock_password_form.dart +++ b/catalyst_voices/apps/voices/lib/pages/registration/widgets/unlock_password_form.dart @@ -55,6 +55,7 @@ class _UnlockPasswordTextField extends StatelessWidget { @override Widget build(BuildContext context) { return VoicesPasswordTextField( + key: const Key('PasswordInputField'), controller: controller, textInputAction: TextInputAction.next, decoration: VoicesTextFieldDecoration( @@ -78,6 +79,7 @@ class _ConfirmUnlockPasswordTextField extends StatelessWidget { @override Widget build(BuildContext context) { return VoicesPasswordTextField( + key: const Key('PasswordConfirmInputField'), controller: controller, decoration: VoicesTextFieldDecoration( labelText: context.l10n.confirmPassword, diff --git a/catalyst_voices/apps/voices/lib/widgets/indicators/voices_password_strength_indicator.dart b/catalyst_voices/apps/voices/lib/widgets/indicators/voices_password_strength_indicator.dart index 41be4d15bd4..92b9126a447 100644 --- a/catalyst_voices/apps/voices/lib/widgets/indicators/voices_password_strength_indicator.dart +++ b/catalyst_voices/apps/voices/lib/widgets/indicators/voices_password_strength_indicator.dart @@ -37,6 +37,7 @@ class _Label extends StatelessWidget { @override Widget build(BuildContext context) { return Text( + key: const Key('PasswordStrengthLabel'), switch (passwordStrength) { PasswordStrength.weak => context.l10n.weakPasswordStrength, PasswordStrength.normal => context.l10n.normalPasswordStrength, @@ -63,6 +64,7 @@ class _Indicator extends StatelessWidget { return SizedBox( height: _foregroundTrackHeight, child: LayoutBuilder( + key: const Key('PasswordStrengthIndicator'), builder: (context, constraints) { final totalWidthOfAllGaps = (PasswordStrength.values.length - 1) * _tracksGap; diff --git a/catalyst_voices/apps/voices/lib/widgets/seed_phrase/seed_phrases_sequencer.dart b/catalyst_voices/apps/voices/lib/widgets/seed_phrase/seed_phrases_sequencer.dart index 6126b193ec5..f83f8a736a1 100644 --- a/catalyst_voices/apps/voices/lib/widgets/seed_phrase/seed_phrases_sequencer.dart +++ b/catalyst_voices/apps/voices/lib/widgets/seed_phrase/seed_phrases_sequencer.dart @@ -41,6 +41,7 @@ class SeedPhrasesSequencer extends StatelessWidget { ), const SizedBox(height: 10), SeedPhrasesPicker( + key: const Key('SeedPhrasesPicker'), words: words, selectedWords: selectedWords, onWordTap: _selectWord, diff --git a/catalyst_voices/apps/voices/lib/widgets/separators/voices_text_divider.dart b/catalyst_voices/apps/voices/lib/widgets/separators/voices_text_divider.dart index c9e90b0d1c0..6758fbd6d78 100644 --- a/catalyst_voices/apps/voices/lib/widgets/separators/voices_text_divider.dart +++ b/catalyst_voices/apps/voices/lib/widgets/separators/voices_text_divider.dart @@ -47,6 +47,7 @@ class VoicesTextDivider extends StatelessWidget { Expanded(child: Divider(indent: indent)), SizedBox(width: nameGap), DefaultTextStyle( + key: const Key('NextStepTitle'), style: (theme.textTheme.bodyLarge ?? const TextStyle()) .copyWith(color: theme.colors.textOnPrimary), child: child, diff --git a/catalyst_voices/apps/voices/lib/widgets/text_field/voices_text_field.dart b/catalyst_voices/apps/voices/lib/widgets/text_field/voices_text_field.dart index cbba4f8a13e..0f497bb6d93 100644 --- a/catalyst_voices/apps/voices/lib/widgets/text_field/voices_text_field.dart +++ b/catalyst_voices/apps/voices/lib/widgets/text_field/voices_text_field.dart @@ -216,6 +216,7 @@ class _VoicesTextFieldState extends State { minHeight: widget.maxLines == null ? 65 : 48, iconBottomSpacing: widget.maxLines == null ? 18 : 0, child: TextFormField( + key: const Key('VoicesTextField'), textAlignVertical: TextAlignVertical.top, autofocus: widget.autofocus, expands: resizable,