diff --git a/.github/workflows/manual-builds.yml b/.github/workflows/manual-builds.yml index 019278cb00..3bef1e5149 100644 --- a/.github/workflows/manual-builds.yml +++ b/.github/workflows/manual-builds.yml @@ -74,6 +74,10 @@ jobs: IMPORTED_HD_ACCOUNT_FIRST_HASH_SHORT_FORM: ${{ secrets.IMPORTED_HD_ACCOUNT_FIRST_HASH_SHORT_FORM }} WATCH_ONLY_PUBLIC_KEY_HASH: ${{ secrets.WATCH_ONLY_PUBLIC_KEY_HASH }} WATCH_ONLY_PUBLIC_KEY_HASH_SHORT_FORM: ${{ secrets.WATCH_ONLY_PUBLIC_KEY_HASH_SHORT_FORM }} + LONG_HD_ACCOUNT_SEED_PHRASE: ${{ secrets.LONG_HD_ACCOUNT_SEED_PHRASE }} + LONG_HD_ACCOUNT_FIRST_PRIVATE_KEY: ${{ secrets.LONG_HD_ACCOUNT_FIRST_PRIVATE_KEY }} + LONG_HD_ACCOUNT_FIRST_PUBLIC_KEY: ${{ secrets.LONG_HD_ACCOUNT_FIRST_PUBLIC_KEY }} + LONG_HD_ACCOUNT_FIRST_HASH_SHORT_FORM: ${{ secrets.LONG_HD_ACCOUNT_FIRST_HASH_SHORT_FORM }} CUSTOM_NETWORK_RPC_URL: ${{ secrets.CUSTOM_NETWORK_RPC_URL }} CUSTOM_NETWORK_SECOND_RPC_URL: ${{ secrets.CUSTOM_NETWORK_SECOND_RPC_URL }} diff --git a/.github/workflows/secrets-setup/action.yml b/.github/workflows/secrets-setup/action.yml index 62c135c3df..2724afee1e 100644 --- a/.github/workflows/secrets-setup/action.yml +++ b/.github/workflows/secrets-setup/action.yml @@ -25,6 +25,10 @@ inputs: required: true TEMPLE_FIREBASE_MESSAGING_VAPID_KEY: required: true + TEMPLE_WALLET_ROUTE3_AUTH_TOKEN: + required: true + TEMPLE_WALLET_MOONPAY_API_KEY: + required: true # [e2e] DEFAULT_HD_ACCOUNT_SEED_PHRASE: required: false @@ -50,14 +54,18 @@ inputs: required: false IMPORTED_HD_ACCOUNT_FIRST_HASH_SHORT_FORM: required: false - TEMPLE_WALLET_ROUTE3_AUTH_TOKEN: - required: true - TEMPLE_WALLET_MOONPAY_API_KEY: - required: true WATCH_ONLY_PUBLIC_KEY_HASH: required: false WATCH_ONLY_PUBLIC_KEY_HASH_SHORT_FORM: required: false + LONG_HD_ACCOUNT_SEED_PHRASE: + required: false + LONG_HD_ACCOUNT_FIRST_PRIVATE_KEY: + required: false + LONG_HD_ACCOUNT_FIRST_PUBLIC_KEY: + required: false + LONG_HD_ACCOUNT_FIRST_HASH_SHORT_FORM: + required: false CUSTOM_NETWORK_RPC_URL: required: false CUSTOM_NETWORK_SECOND_RPC_URL: @@ -107,6 +115,10 @@ runs: IMPORTED_HD_ACCOUNT_FIRST_HASH_SHORT_FORM=${{ inputs.IMPORTED_HD_ACCOUNT_FIRST_HASH_SHORT_FORM }} WATCH_ONLY_PUBLIC_KEY_HASH=${{ inputs.WATCH_ONLY_PUBLIC_KEY_HASH }} WATCH_ONLY_PUBLIC_KEY_HASH_SHORT_FORM=${{ inputs.WATCH_ONLY_PUBLIC_KEY_HASH_SHORT_FORM }} + LONG_HD_ACCOUNT_SEED_PHRASE=${{ inputs.LONG_HD_ACCOUNT_SEED_PHRASE }} + LONG_HD_ACCOUNT_FIRST_PRIVATE_KEY=${{ inputs.LONG_HD_ACCOUNT_FIRST_PRIVATE_KEY }} + LONG_HD_ACCOUNT_FIRST_PUBLIC_KEY=${{ inputs.LONG_HD_ACCOUNT_FIRST_PUBLIC_KEY }} + LONG_HD_ACCOUNT_FIRST_HASH_SHORT_FORM=${{ inputs.LONG_HD_ACCOUNT_FIRST_HASH_SHORT_FORM }} CUSTOM_NETWORK_RPC_URL=${{ inputs.CUSTOM_NETWORK_RPC_URL }} CUSTOM_NETWORK_SECOND_RPC_URL=${{ inputs.CUSTOM_NETWORK_SECOND_RPC_URL }} EOF diff --git a/e2e/.env.dist b/e2e/.env.dist index ab121bb842..8ec4075450 100644 --- a/e2e/.env.dist +++ b/e2e/.env.dist @@ -18,6 +18,13 @@ IMPORTED_HD_ACCOUNT_FIRST_PUBLIC_KEY_HASH= IMPORTED_HD_ACCOUNT_FIRST_HASH_SHORT_FORM= +LONG_HD_ACCOUNT_SEED_PHRASE= + +LONG_HD_ACCOUNT_FIRST_PRIVATE_KEY= +LONG_HD_ACCOUNT_FIRST_PUBLIC_KEY= +LONG_HD_ACCOUNT_FIRST_HASH_SHORT_FORM= + + WATCH_ONLY_PUBLIC_KEY_HASH= WATCH_ONLY_PUBLIC_KEY_HASH_SHORT_FORM= diff --git a/e2e/src/features/home.feature b/e2e/src/features/home.feature index cc9ca5f8cd..4273769825 100644 --- a/e2e/src/features/home.feature +++ b/e2e/src/features/home.feature @@ -14,6 +14,7 @@ Feature: Check functional on the Home page # empty state error And The Empty State Text on the Home page has correct No assets found value And I clear Search Assets Input (Tokens) value on the Assets page + And The Asset Item Button is displayed on the Assets page # hide 0 balances And I press Manage Dropdown Button on the Assets page diff --git a/e2e/src/features/import-account-by-mnemonic.feature b/e2e/src/features/import-account-by-mnemonic.feature index 09a6fb05b6..1caf77d36b 100644 --- a/e2e/src/features/import-account-by-mnemonic.feature +++ b/e2e/src/features/import-account-by-mnemonic.feature @@ -13,7 +13,190 @@ Feature: Import Account by Mnemonic And I select Mnemonic tab And I am on the ImportAccountMnemonic page - And I enter second mnemonic + And I enter importedSeedPhrase mnemonic on the ImportAccountMnemonic page And I press Mnemonic Import Button on the Import Account(Mnemonic) page Then I reveal a private key and compare with importedFirstPrivateKey + + Scenario: As a user, I'd like to import account by mnemonic with derivation path + password field + Given I have imported an existing account + + And I press Account Icon on the Header page + And I am on the AccountsDropdown page + + And I press Import Account Button on the Account Drop-down page + And I am on the ImportAccountTab page + + And I select Mnemonic tab + And I am on the ImportAccountMnemonic page + + And I enter importedSeedPhrase mnemonic on the ImportAccountMnemonic page + And I press Mnemonic Import Button on the Import Account(Mnemonic) page + + And I am on the Home page + And I check if importedAccountShortHash is corresponded to the selected account + +# importing an account with derivation path + And I press Account Icon on the Header page + And I am on the AccountsDropdown page + + And I press Import Account Button on the Account Drop-down page + And I am on the ImportAccountTab page + + And I select Mnemonic tab + And I am on the ImportAccountMnemonic page + + And I enter importedSeedPhrase mnemonic on the ImportAccountMnemonic page + + And I scroll 200 pixels on the ImportAccountMnemonic page + And I press Custom Derivation Path Button on the Import Account(Mnemonic) page + And I clear Custom Derivation Path Input value on the Import Account(Mnemonic) page + And I enter customDerivationPath into Custom Derivation Path Input on the Import Account(Mnemonic) page + And I scroll 900 pixels on the ImportAccountMnemonic page + And I press Mnemonic Import Button on the Import Account(Mnemonic) page + + And I am on the Home page + And I check if importedAccountDerPathShortHash is corresponded to the selected account + +# importing an account with additional 'Password' input + And I press Account Icon on the Header page + And I am on the AccountsDropdown page + + And I press Import Account Button on the Account Drop-down page + And I am on the ImportAccountTab page + + And I select Mnemonic tab + And I am on the ImportAccountMnemonic page + + And I enter importedSeedPhrase mnemonic on the ImportAccountMnemonic page + And I scroll 900 pixels on the ImportAccountMnemonic page + And I enter amount_1 into Mnemonic Password Input on the Import Account(Mnemonic) page + And I press Mnemonic Import Button on the Import Account(Mnemonic) page + + And I am on the Home page + Then I check if importedAccountByPasswordShortHash is corresponded to the selected account + + +@dev + Scenario: Import account by mnemonic validation + negative cases + Given I have imported an existing account + + And I press Account Icon on the Header page + And I am on the AccountsDropdown page + + And I press Import Account Button on the Account Drop-down page + And I am on the ImportAccountTab page + + And I select Mnemonic tab + And I am on the ImportAccountMnemonic page +# validation checks 12 words seed + And I scroll 900 pixels on the ImportAccountMnemonic page + And I press Mnemonic Import Button on the Import Account(Mnemonic) page + And I got the validation-error 'Seed phrase must contain 12 words' with Mnemonic Validation Error Text element on the Import (Account/Wallet) page + And I scroll -300 pixels on the ImportAccountMnemonic page + And The Mnemonic Drop Down Button on the Import (Account/Wallet) page has correct My Seed phrase is 12 words value +# validation checks 24 words seed + And I press Mnemonic Drop Down Button on the Import (Account/Wallet) page + And I select mnemonic with 24 words + And I scroll 900 pixels on the ImportAccountMnemonic page + And I press Mnemonic Import Button on the Import Account(Mnemonic) page + And I got the validation-error 'Seed phrase must contain 24 words' with Mnemonic Validation Error Text element on the Import (Account/Wallet) page + + And I reload the page + And I am on the ImportAccountMnemonic page + +# validation checks word inputs with 'invalidRandomSeedPhrase' + And I enter invalidRandomSeedPhrase mnemonic on the ImportAccountMnemonic page + And I scroll 300 pixels on the ImportAccountMnemonic page + And I press Mnemonic Import Button on the Import Account(Mnemonic) page + And I got the validation-error 'Invalid Seed Phrase' with Mnemonic Validation Error Text element on the Import (Account/Wallet) page + + And I scroll -300 pixels on the ImportAccountMnemonic page + And I clear entered mnemonic on the ImportAccountMnemonic page + +# validation checks word inputs with 'incorrectSeedPhrase' + And I enter incorrectSeedPhrase mnemonic on the ImportAccountMnemonic page + And I scroll 300 pixels on the ImportAccountMnemonic page + And I press Mnemonic Import Button on the Import Account(Mnemonic) page + And I got the validation-error 'Invalid Seed PhraseMake sure the words spelled correctly' with Mnemonic Validation Error Text element on the Import (Account/Wallet) page + + And I scroll -300 pixels on the ImportAccountMnemonic page + And I clear entered mnemonic on the ImportAccountMnemonic page + +# validation checks word inputs with 'invalidSeedPhrase' + And I enter invalidSeedPhrase mnemonic on the ImportAccountMnemonic page + And I scroll 300 pixels on the ImportAccountMnemonic page + And I press Mnemonic Import Button on the Import Account(Mnemonic) page + And I got the validation-error 'Invalid Seed Phrase' with Mnemonic Validation Error Text element on the Import (Account/Wallet) page + + And I scroll -300 pixels on the ImportAccountMnemonic page + And I clear entered mnemonic on the ImportAccountMnemonic page + +# validation checks custom derivation path input + And I scroll 200 pixels on the ImportAccountMnemonic page + And I press Custom Derivation Path Button on the Import Account(Mnemonic) page + And I clear Custom Derivation Path Input value on the Import Account(Mnemonic) page + +# importing 24 words seed + And I scroll -300 pixels on the ImportAccountMnemonic page + And I press Mnemonic Drop Down Button on the Import (Account/Wallet) page + And I select mnemonic with 24 words + And I enter longSeedPhrase24 mnemonic on the ImportAccountMnemonic page + And I scroll 900 pixels on the ImportAccountMnemonic page + + And I press Mnemonic Import Button on the Import Account(Mnemonic) page + + And I am on the Home page + And I check if longFirstAccountShortHash is corresponded to the selected account + +# checking derivation type validation + And I press Account Icon on the Header page + And I am on the AccountsDropdown page + + And I press Import Account Button on the Account Drop-down page + And I am on the ImportAccountTab page + + And I select Mnemonic tab + And I am on the ImportAccountMnemonic page + + And I enter importedSeedPhrase mnemonic on the ImportAccountMnemonic page + And I press Custom Derivation Path Button on the Import Account(Mnemonic) page + And I scroll 900 pixels on the ImportAccountMnemonic page + And I clear Custom Derivation Path Input value on the Import Account(Mnemonic) page + And I enter shortRandomContent into Custom Derivation Path Input on the Import Account(Mnemonic) page + And I press Mnemonic Import Button on the Import Account(Mnemonic) page + + And I got the validation-error 'Must start with 'm'' with Input Error element on the Universal Component page + + # invalid path validation + And I clear Custom Derivation Path Input value on the Import Account(Mnemonic) page + And I enter invalidDerivationPath into Custom Derivation Path Input on the Import Account(Mnemonic) page + And I press Mnemonic Import Button on the Import Account(Mnemonic) page + + And I got the validation-error 'Invalid path' with Input Error element on the Universal Component page + + And I clear Custom Derivation Path Input value on the Import Account(Mnemonic) page + And I enter secondInvalidDerivationPath into Custom Derivation Path Input on the Import Account(Mnemonic) page + And I press Mnemonic Import Button on the Import Account(Mnemonic) page + + And I got the validation-error 'Invalid path' with Input Error element on the Universal Component page + + And I clear Custom Derivation Path Input value on the Import Account(Mnemonic) page + And I enter thirdInvalidDerivationPath into Custom Derivation Path Input on the Import Account(Mnemonic) page + And I press Mnemonic Import Button on the Import Account(Mnemonic) page + + And I got the validation-error 'Invalid path' with Input Error element on the Universal Component page + + And I clear Custom Derivation Path Input value on the Import Account(Mnemonic) page + And I enter fourthInvalidDerivationPath into Custom Derivation Path Input on the Import Account(Mnemonic) page + And I press Mnemonic Import Button on the Import Account(Mnemonic) page + + And I got the validation-error 'Invalid path' with Input Error element on the Universal Component page + +# valid importing to finish the scenario + And I clear Custom Derivation Path Input value on the Import Account(Mnemonic) page + And I enter basicDerivationPath into Custom Derivation Path Input on the Import Account(Mnemonic) page + And I press Mnemonic Import Button on the Import Account(Mnemonic) page + + And I am on the Home page + Then I check if importedAccountShortHash is corresponded to the selected account diff --git a/e2e/src/features/import-account-by-private-key.feature b/e2e/src/features/import-account-by-private-key.feature index 0b09df1553..3994fa1b60 100644 --- a/e2e/src/features/import-account-by-private-key.feature +++ b/e2e/src/features/import-account-by-private-key.feature @@ -17,3 +17,42 @@ Feature: Import Account by Private Key And I press Private Key Import Button on the Import Account(Private Key) page Then I reveal a private key and compare with importedFirstPrivateKey + + + + Scenario: Check validation importing by private key + Given I have imported an existing account + + And I press Account Icon on the Header page + And I am on the AccountsDropdown page + + And I press Import Account Button on the Account Drop-down page + And I am on the ImportAccountTab page + + And I select Private Key tab + And I am on the ImportAccountPrivateKey page + + And I press Private Key Import Button on the Import Account(Private Key) page + And I got the validation-error 'Required' with Input Error element on the Universal Component page + + And I enter shortRandomContent into Private Key Input on the Import Account(Private Key) page + And I press Private Key Import Button on the Import Account(Private Key) page +# checking alert type , title and description of the error + And I got the 'Error' error with Alert title Text element on the Alert page + And I got the validation-error 'Failed to import account. This may happen because provided Key is invalid' with Alert description Text element on the Alert page + + And I clear Private Key Input value on the Import Account(Private Key) page + And I enter defaultFirstPrivateKey into Private Key Input on the Import Account(Private Key) page + And I press Private Key Import Button on the Import Account(Private Key) page + # checking duplicate importing account error + And I got the 'Error' error with Alert title Text element on the Alert page + And I got the validation-error 'Account already exists' with Alert description Text element on the Alert page + + And I clear Private Key Input value on the Import Account(Private Key) page + And I enter importedFirstPrivateKey into Private Key Input on the Import Account(Private Key) page + And I press Private Key Import Button on the Import Account(Private Key) page + + And I am on the Home page + Then I check if importedAccountShortHash is corresponded to the selected account + + diff --git a/e2e/src/features/import-account-by-public-key.feature b/e2e/src/features/import-account-by-public-key.feature index 5b0e2989f3..1157c19223 100644 --- a/e2e/src/features/import-account-by-public-key.feature +++ b/e2e/src/features/import-account-by-public-key.feature @@ -17,3 +17,33 @@ Feature: Import an account by public key (Watch-only) And I press Watch Only Import Button on the Import Account(Watch-Only) page Then I check if watchOnlyAccountShortHash is corresponded to the selected account + + Scenario: Check validation importing by public key + Given I have imported an existing account + + And I press Account Icon on the Header page + And I am on the AccountsDropdown page + + And I press Import Account Button on the Account Drop-down page + And I am on the ImportAccountTab page + + And I select Watch-only tab + And I am on the ImportAccountWatchOnly page + + And I enter shortRandomContent into Watch Only Input on the Import Account(Watch-Only) page + And I press Watch Only Import Button on the Import Account(Watch-Only) page + And I got the validation-error 'Invalid address or domain name' with Input Error element on the Universal Component page + + And I clear Watch Only Input value on the Import Account(Watch-Only) page + And I enter defaultFirstPublicKey into Watch Only Input on the Import Account(Watch-Only) page + And I press Watch Only Import Button on the Import Account(Watch-Only) page +# checking alert type , title and description of the error + And I got the 'Error' error with Alert title Text element on the Alert page + And I got the validation-error 'Account already exists' with Alert description Text element on the Alert page + + And I clear Watch Only Input value on the Import Account(Watch-Only) page + And I clear Watch Only Input value on the Import Account(Watch-Only) page + And I enter watchOnlyPublicKey into Watch Only Input on the Import Account(Watch-Only) page + And I press Watch Only Import Button on the Import Account(Watch-Only) page + + Then I check if watchOnlyAccountShortHash is corresponded to the selected account diff --git a/e2e/src/features/import-existing-wallet.feature b/e2e/src/features/import-existing-wallet.feature index 7889dff6cf..4091f0f5a4 100644 --- a/e2e/src/features/import-existing-wallet.feature +++ b/e2e/src/features/import-existing-wallet.feature @@ -6,7 +6,7 @@ Feature: Import existing wallet And I press Import Existing Wallet button on the Welcome page And I am on the ImportExistingWallet page - And I enter default mnemonic + And I enter defaultSeedPhrase mnemonic on the ImportExistingWallet page And I press Next button on the Import Existing Seed Phrase page And I am on the SetWallet page @@ -29,7 +29,7 @@ Feature: Import existing wallet And I press Import Existing Wallet button on the Welcome page And I am on the ImportExistingWallet page - And I enter default mnemonic + And I enter defaultSeedPhrase mnemonic on the ImportExistingWallet page And I press Next button on the Import Existing Seed Phrase page And I am on the SetWallet page @@ -66,7 +66,7 @@ Feature: Import existing wallet And I press Import Existing Wallet button on the Welcome page And I am on the ImportExistingWallet page - And I enter default mnemonic + And I enter defaultSeedPhrase mnemonic on the ImportExistingWallet page And I press Next button on the Import Existing Seed Phrase page And I am on the SetWallet page diff --git a/e2e/src/features/remove-account.feature b/e2e/src/features/remove-account.feature index 6ac8d627e3..6d7e618cb6 100644 --- a/e2e/src/features/remove-account.feature +++ b/e2e/src/features/remove-account.feature @@ -13,7 +13,7 @@ Feature: Remove an account And I select Mnemonic tab And I am on the ImportAccountMnemonic page - And I enter second mnemonic + And I enter importedSeedPhrase mnemonic on the ImportAccountMnemonic page And I press Mnemonic Import Button on the Import Account(Mnemonic) page And I am on the Home page @@ -31,7 +31,7 @@ Feature: Remove an account And I press Remove Button on the Remove Account page And I am on the Home page - And I check if defaultSecondAccountShortHash is corresponded to the selected account + And I check if defaultFirstAccountShortHash is corresponded to the selected account # Remove an imported account by private key @@ -122,7 +122,7 @@ Feature: Remove an account And I select Mnemonic tab And I am on the ImportAccountMnemonic page - And I enter second mnemonic + And I enter importedSeedPhrase mnemonic on the ImportAccountMnemonic page And I press Mnemonic Import Button on the Import Account(Mnemonic) page And I am on the Home page diff --git a/e2e/src/features/switch-account.feature b/e2e/src/features/switch-account.feature index 4ee705f41a..88d636e694 100644 --- a/e2e/src/features/switch-account.feature +++ b/e2e/src/features/switch-account.feature @@ -1,5 +1,5 @@ Feature: Switch account -@dev + Scenario: As a user, I'd like to switch between my accounts Given I have imported an existing account # creating or restoring second hd account diff --git a/e2e/src/features/unlock-screen.feature b/e2e/src/features/unlock-screen.feature index c05164b9c6..ad4d773ff9 100644 --- a/e2e/src/features/unlock-screen.feature +++ b/e2e/src/features/unlock-screen.feature @@ -124,7 +124,7 @@ Feature: Unlock Screen # restore a wallet another (second) mnemonic And I am on the ImportExistingWallet page And I got the 'Attention!' warning with Alert title Text element on the Alert page - And I enter default mnemonic + And I enter defaultSeedPhrase mnemonic on the ImportExistingWallet page And I press Next button on the Import Existing Seed Phrase page And I am on the SetWallet page diff --git a/e2e/src/page-objects/pages/import-account-tabs/import-account-mnemonic-tab.page.ts b/e2e/src/page-objects/pages/import-account-tabs/import-account-mnemonic-tab.page.ts index 6e17f49e20..7f4f05251e 100644 --- a/e2e/src/page-objects/pages/import-account-tabs/import-account-mnemonic-tab.page.ts +++ b/e2e/src/page-objects/pages/import-account-tabs/import-account-mnemonic-tab.page.ts @@ -1,7 +1,9 @@ import { ImportAccountSelectors } from 'src/app/pages/ImportAccount/selectors'; import { Page } from 'e2e/src/classes/page.class'; -import { createPageElement, findElements } from 'e2e/src/utils/search.utils'; +import { EMPTY_WORD_FOR_INPUTS } from 'e2e/src/utils/input-data.utils'; +import { clearDataFromInput, createPageElement, findElement, findElements } from 'e2e/src/utils/search.utils'; +import { SHORT_TIMEOUT } from 'e2e/src/utils/timing.utils'; export class ImportAccountMnemonicTab extends Page { mnemonicWordInput = createPageElement(ImportAccountSelectors.mnemonicWordInput); @@ -22,7 +24,31 @@ export class ImportAccountMnemonicTab extends Page { const word = wordsArray[i]; const input = wordsInputs[i]; - await input.type(word); + await input.type(word.replace(EMPTY_WORD_FOR_INPUTS, '')); } } + + async clearSeedPhrase() { + const wordsInputs = await findElements(ImportAccountSelectors.mnemonicWordInput); + + for (let i = 0; i < wordsInputs.length; i++) { + const input = wordsInputs[i]; + + await input.focus(); + await clearDataFromInput(); + } + } + + async selectMnemonicWordsCount(words: string) { + const mnemonicWordsCount = await findElement( + ImportAccountSelectors.mnemonicWordsRadioButton, + { words }, + SHORT_TIMEOUT, + `Variant of Seed Phrase with ${words} words is not found: + 1) Selected variant is not displayed (bug/issue) + 2) Seed phrase can contain only 12, 15, 18, 21, 24 words` + ); + + await mnemonicWordsCount.click(); + } } diff --git a/e2e/src/page-objects/pages/importing-existing-wallet.page.ts b/e2e/src/page-objects/pages/importing-existing-wallet.page.ts index af2003e0e6..b46509f5ed 100644 --- a/e2e/src/page-objects/pages/importing-existing-wallet.page.ts +++ b/e2e/src/page-objects/pages/importing-existing-wallet.page.ts @@ -1,7 +1,7 @@ import { ImportFromSeedPhraseSelectors } from 'src/app/pages/NewWallet/import/ImportSeedPhrase/ImportFromSeedPhrase.selectors'; import { Page } from '../../classes/page.class'; -import { createPageElement, findElements } from '../../utils/search.utils'; +import { clearDataFromInput, createPageElement, findElements } from '../../utils/search.utils'; export class ImportExistingWalletPage extends Page { nextButton = createPageElement(ImportFromSeedPhraseSelectors.nextButton); @@ -23,4 +23,15 @@ export class ImportExistingWalletPage extends Page { await input.type(word); } } + + async clearSeedPhrase() { + const wordsInputs = await findElements(ImportFromSeedPhraseSelectors.wordInput); + + for (let i = 0; i < wordsInputs.length; i++) { + const input = wordsInputs[i]; + + await input.focus(); + await clearDataFromInput(); + } + } } diff --git a/e2e/src/step-definitions/common.steps.ts b/e2e/src/step-definitions/common.steps.ts index 8c1a71346d..12bb174104 100644 --- a/e2e/src/step-definitions/common.steps.ts +++ b/e2e/src/step-definitions/common.steps.ts @@ -62,3 +62,7 @@ Given( await Pages[page].scrollTo(countOfScroll); } ); + +Given(/I reload the page/, async () => { + await BrowserContext.page.reload(); +}); diff --git a/e2e/src/step-definitions/import-account.steps.ts b/e2e/src/step-definitions/import-account.steps.ts deleted file mode 100644 index eee4f43c6f..0000000000 --- a/e2e/src/step-definitions/import-account.steps.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Given } from '@cucumber/cucumber'; - -import { MEDIUM_TIMEOUT } from 'e2e/src/utils/timing.utils'; - -import { Pages } from '../page-objects'; -import { envVars } from '../utils/env.utils'; - -Given(/I enter second mnemonic/, { timeout: MEDIUM_TIMEOUT }, async () => { - await Pages.ImportAccountMnemonic.enterSeedPhrase(envVars.IMPORTED_HD_ACCOUNT_SEED_PHRASE); -}); - -Given(/I select (.*) tab/, async (tabName: string) => { - await Pages.ImportAccountTab.selectTab(tabName); -}); diff --git a/e2e/src/step-definitions/import-existing-wallet.steps.ts b/e2e/src/step-definitions/import-existing-wallet.steps.ts deleted file mode 100644 index 2d953829e1..0000000000 --- a/e2e/src/step-definitions/import-existing-wallet.steps.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Given } from '@cucumber/cucumber'; - -import { MEDIUM_TIMEOUT } from 'e2e/src/utils/timing.utils'; - -import { BrowserContext } from '../classes/browser-context.class'; -import { Pages } from '../page-objects'; - -Given(/I enter default mnemonic/, { timeout: MEDIUM_TIMEOUT }, async () => { - await Pages.ImportExistingWallet.enterSeedPhrase(BrowserContext.seedPhrase); -}); diff --git a/e2e/src/step-definitions/import-wallet-or-account.steps.ts b/e2e/src/step-definitions/import-wallet-or-account.steps.ts new file mode 100644 index 0000000000..79b180963c --- /dev/null +++ b/e2e/src/step-definitions/import-wallet-or-account.steps.ts @@ -0,0 +1,31 @@ +import { Given } from '@cucumber/cucumber'; + +import { iEnterValues } from 'e2e/src/utils/input-data.utils'; +import { MEDIUM_TIMEOUT } from 'e2e/src/utils/timing.utils'; + +import { Pages } from '../page-objects'; + +type mnemonicPage = 'ImportAccountMnemonic' | 'ImportExistingWallet'; + +Given( + /I enter (.*) mnemonic on the (\w+) page/, + { timeout: MEDIUM_TIMEOUT }, + async (mnemonic: keyof typeof iEnterValues, page: mnemonicPage) => { + const wrongMnemonic = iEnterValues[mnemonic]; + if (wrongMnemonic === undefined) throw new Error(`${mnemonic} key doesn't exist in the 'iEnterValues' object`); + + await Pages[page].enterSeedPhrase(wrongMnemonic); + } +); + +Given(/I clear entered mnemonic on the (\w+) page/, { timeout: MEDIUM_TIMEOUT }, async (page: mnemonicPage) => { + await Pages[page].clearSeedPhrase(); +}); + +Given(/I select (.*) tab/, async (tabName: string) => { + await Pages.ImportAccountTab.selectTab(tabName); +}); + +Given(/I select mnemonic with (.*) words/, { timeout: MEDIUM_TIMEOUT }, async (wordsCount: string) => { + await Pages.ImportAccountMnemonic.selectMnemonicWordsCount(wordsCount); +}); diff --git a/e2e/src/step-definitions/shared.steps.ts b/e2e/src/step-definitions/shared.steps.ts index 0f963e7aee..b940165932 100644 --- a/e2e/src/step-definitions/shared.steps.ts +++ b/e2e/src/step-definitions/shared.steps.ts @@ -42,7 +42,10 @@ const hashObjectShortForm = { defaultFirstAccountShortHash: envVars.DEFAULT_HD_ACCOUNT_FIRST_HASH_SHORT_FORM, defaultSecondAccountShortHash: envVars.DEFAULT_HD_ACCOUNT_SECOND_HASH_SHORT_FORM, importedAccountShortHash: envVars.IMPORTED_HD_ACCOUNT_FIRST_HASH_SHORT_FORM, - watchOnlyAccountShortHash: envVars.WATCH_ONLY_PUBLIC_KEY_HASH_SHORT_FORM + importedAccountDerPathShortHash: 'tz1RPXf...RE8q', + importedAccountByPasswordShortHash: 'tz1ZfC8...PcHE', // By additional (optional) 'Password' input + watchOnlyAccountShortHash: envVars.WATCH_ONLY_PUBLIC_KEY_HASH_SHORT_FORM, + longFirstAccountShortHash: envVars.LONG_HD_ACCOUNT_FIRST_HASH_SHORT_FORM }; Given( diff --git a/e2e/src/utils/env.utils.ts b/e2e/src/utils/env.utils.ts index 4d6fb07cb6..ddf8c0392d 100644 --- a/e2e/src/utils/env.utils.ts +++ b/e2e/src/utils/env.utils.ts @@ -17,6 +17,10 @@ export const envVars = { IMPORTED_HD_ACCOUNT_FIRST_PRIVATE_KEY: getEnv('IMPORTED_HD_ACCOUNT_FIRST_PRIVATE_KEY'), IMPORTED_HD_ACCOUNT_FIRST_PUBLIC_KEY_HASH: getEnv('IMPORTED_HD_ACCOUNT_FIRST_PUBLIC_KEY_HASH'), IMPORTED_HD_ACCOUNT_FIRST_HASH_SHORT_FORM: getEnv('IMPORTED_HD_ACCOUNT_FIRST_HASH_SHORT_FORM'), + LONG_HD_ACCOUNT_SEED_PHRASE: getEnv('LONG_HD_ACCOUNT_SEED_PHRASE'), + LONG_HD_ACCOUNT_FIRST_PRIVATE_KEY: getEnv('LONG_HD_ACCOUNT_FIRST_PRIVATE_KEY'), + LONG_HD_ACCOUNT_FIRST_PUBLIC_KEY: getEnv('LONG_HD_ACCOUNT_FIRST_PUBLIC_KEY'), + LONG_HD_ACCOUNT_FIRST_HASH_SHORT_FORM: getEnv('LONG_HD_ACCOUNT_FIRST_HASH_SHORT_FORM'), WATCH_ONLY_PUBLIC_KEY_HASH: getEnv('WATCH_ONLY_PUBLIC_KEY_HASH'), WATCH_ONLY_PUBLIC_KEY_HASH_SHORT_FORM: getEnv('WATCH_ONLY_PUBLIC_KEY_HASH_SHORT_FORM'), CUSTOM_NETWORK_RPC_URL: getEnv('CUSTOM_NETWORK_RPC_URL'), diff --git a/e2e/src/utils/input-data.utils.ts b/e2e/src/utils/input-data.utils.ts index 57560a73e3..5bf9c4cecc 100644 --- a/e2e/src/utils/input-data.utils.ts +++ b/e2e/src/utils/input-data.utils.ts @@ -6,19 +6,44 @@ export const iComparePrivateKeys = { }; const generateRandomContent = () => { - const wordsArray = ['apple', 'banana', 'carrot', 'dog', 'elephant', 'fish', 'grape', 'hat', 'ice cream', 'jungle']; + const wordsArray = ['apple', 'banana', 'carrot', 'dog', 'elephant', 'fish', 'grape', 'hat', 'cream', 'jungle']; const randomWord = Math.floor(Math.random() * wordsArray.length); return wordsArray[randomWord] + Math.floor(Math.random() * 10000).toString(); }; +const randomSeedWord = () => { + const wordsArray = ['about', 'document', 'lesson', 'scatter', 'above', 'dog', 'letter', 'abuse', 'science']; + return wordsArray[Math.floor(Math.random() * wordsArray.length)]; +}; + +export const EMPTY_WORD_FOR_INPUTS = 'EMPTY_WORD'; + export const iEnterValues = { ...iComparePrivateKeys, - defaultSeedPhrase: envVars.DEFAULT_HD_ACCOUNT_SEED_PHRASE, + defaultFirstPrivateKey: envVars.DEFAULT_HD_ACCOUNT_FIRST_PRIVATE_KEY, + defaultFirstPublicKey: envVars.DEFAULT_HD_ACCOUNT_FIRST_PUBLIC_KEY_HASH, defaultPassword: envVars.DEFAULT_PASSWORD, + watchOnlyPublicKey: envVars.WATCH_ONLY_PUBLIC_KEY_HASH, bakerAddress: '', + // Derivation paths + basicDerivationPath: `m/44'/1729'/0'/0'`, // first account in HD (main) + customDerivationPath: `m/44'/1729'/10'/0'`, // eleventh account in HD + invalidDerivationPath: `m/broken44'/1729'/0'/0'`, + secondInvalidDerivationPath: `m/44'/17broken29'/0'/0'`, + thirdInvalidDerivationPath: `m/44'/1729'/0broken'/0'`, + fourthInvalidDerivationPath: `m/44'/1729'/0'/0broken'`, + + // For testing mnemonic inputs + defaultSeedPhrase: envVars.DEFAULT_HD_ACCOUNT_SEED_PHRASE, + importedSeedPhrase: envVars.IMPORTED_HD_ACCOUNT_SEED_PHRASE, + longSeedPhrase24: envVars.LONG_HD_ACCOUNT_SEED_PHRASE, + invalidSeedPhrase: 'scissors dolphin light ability voice voice sail cruel labor dry screen feature', // words from BIP39 + invalidRandomSeedPhrase: `${randomSeedWord()} document ${EMPTY_WORD_FOR_INPUTS} ${randomSeedWord()} ${randomSeedWord()} ${randomSeedWord()} dog ${EMPTY_WORD_FOR_INPUTS} ${randomSeedWord()} ${randomSeedWord()} ${EMPTY_WORD_FOR_INPUTS} ${randomSeedWord()}`, + incorrectSeedPhrase: 'alsla sadh 123213 sadaj asdj sajd jewd wedn wedn wedbn wedhb criwl', + // For input validation shortRandomContent: generateRandomContent(), longRandomContent: 'long random content for test + long +' + generateRandomContent(), diff --git a/e2e/src/utils/search.utils.ts b/e2e/src/utils/search.utils.ts index bc0070db2e..6d297a20ab 100644 --- a/e2e/src/utils/search.utils.ts +++ b/e2e/src/utils/search.utils.ts @@ -89,11 +89,7 @@ class PageElement { } async clearInput() { - await BrowserContext.page.keyboard.press('End'); - await BrowserContext.page.keyboard.down('Shift'); - await BrowserContext.page.keyboard.press('Home'); - await BrowserContext.page.keyboard.up('Shift'); - await BrowserContext.page.keyboard.press('Backspace'); + await clearDataFromInput(); } async getText() { const element = await this.findElement(); @@ -132,7 +128,7 @@ export const getElementText = (element: ElementHandle) => return innerElement.value; } - const textContent = innerElement.textContent; + const textContent = innerElement.textContent?.replace(/\n/g, ' '); if (textContent == null) { throw new Error("Element's content is not text!"); @@ -156,3 +152,11 @@ const buildNotSelector = (notSelectors: OtherSelectors) => { const pairs = buildSelectorPairs(notSelectors); return `:not([${pairs.join(']):not([')}])`; }; + +export const clearDataFromInput = async () => { + await BrowserContext.page.keyboard.press('End'); + await BrowserContext.page.keyboard.down('Shift'); + await BrowserContext.page.keyboard.press('Home'); + await BrowserContext.page.keyboard.up('Shift'); + await BrowserContext.page.keyboard.press('Backspace'); +}; diff --git a/src/app/atoms/Alert.selectors.ts b/src/app/atoms/Alert.selectors.ts index c27bd1c506..b3a72ee2a2 100644 --- a/src/app/atoms/Alert.selectors.ts +++ b/src/app/atoms/Alert.selectors.ts @@ -1,3 +1,4 @@ export enum AlertSelectors { - alertTitle = 'Alert/Alert title Text' + alertTitle = 'Alert/Alert title Text', + alertDescription = 'Alert/Alert description Text' } diff --git a/src/app/atoms/Alert.tsx b/src/app/atoms/Alert.tsx index 9f91f1a19e..3ea1261f6e 100644 --- a/src/app/atoms/Alert.tsx +++ b/src/app/atoms/Alert.tsx @@ -74,7 +74,10 @@ export const Alert: FC = ({ )} {description && ( -
+
{description}
)} diff --git a/src/app/pages/ImportAccount/ByMnemonicForm.tsx b/src/app/pages/ImportAccount/ByMnemonicForm.tsx index 9b7449f708..c100781aa1 100644 --- a/src/app/pages/ImportAccount/ByMnemonicForm.tsx +++ b/src/app/pages/ImportAccount/ByMnemonicForm.tsx @@ -7,8 +7,8 @@ import { Alert, FormField, FormSubmitButton } from 'app/atoms'; import { DEFAULT_DERIVATION_PATH, formatMnemonic } from 'app/defaults'; import { ReactComponent as OkIcon } from 'app/icons/ok.svg'; import { isSeedPhraseFilled, SeedPhraseInput } from 'app/templates/SeedPhraseInput'; -import { useFormAnalytics } from 'lib/analytics'; -import { TID, T, t } from 'lib/i18n'; +import { setTestID, useFormAnalytics } from 'lib/analytics'; +import { T, t, TID } from 'lib/i18n'; import { useTempleClient, validateDerivationPath } from 'lib/temple/front'; import { delay } from 'lib/utils'; @@ -162,6 +162,11 @@ export const ByMnemonicForm: FC = () => { padding: '0.4rem 0.375rem 0.4rem 0.375rem' }} onClick={handleClick} + {...setTestID( + dp.type === 'default' + ? ImportAccountSelectors.defaultAccountButton + : ImportAccountSelectors.customDerivationPathButton + )} >
@@ -190,6 +195,7 @@ export const ByMnemonicForm: FC = () => { placeholder={t('derivationPathExample2')} errorCaption={errors.customDerivationPath?.message} containerClassName="mb-6" + testID={ImportAccountSelectors.customDerivationPathInput} /> )} diff --git a/src/app/pages/ImportAccount/selectors.ts b/src/app/pages/ImportAccount/selectors.ts index fdb23324fe..1e30461186 100644 --- a/src/app/pages/ImportAccount/selectors.ts +++ b/src/app/pages/ImportAccount/selectors.ts @@ -5,8 +5,14 @@ export enum ImportAccountSelectors { privateKeyImportButton = 'Import Account(Private Key)/Private Key Import Button', mnemonicWordInput = 'Import Account(Mnemonic)/Mnemonic Word Input', + mnemonicDropDownButton = 'Import (Account/Wallet)/Mnemonic Drop Down Button', + mnemonicWordsRadioButton = 'Import (Account/Wallet)/Mnemonic Words Radio Button', + defaultAccountButton = 'Import Account(Mnemonic)/Default Account (the first one) Button', + customDerivationPathButton = 'Import Account(Mnemonic)/Custom Derivation Path Button', + customDerivationPathInput = 'Import Account(Mnemonic)/Custom Derivation Path Input', mnemonicPasswordInput = 'Import Account(Mnemonic)/Mnemonic Password Input', mnemonicImportButton = 'Import Account(Mnemonic)/Mnemonic Import Button', + mnemonicValidationErrorText = 'Import (Account/Wallet)/Mnemonic Validation Error Text', watchOnlyInput = 'Import Account(Watch-Only)/Watch Only Input', watchOnlyImportButton = 'Import Account(Watch-Only)/Watch Only Import Button', diff --git a/src/app/templates/SeedPhraseInput/SeedLengthSelect/SeedLengthOption/SeedLengthOption.tsx b/src/app/templates/SeedPhraseInput/SeedLengthSelect/SeedLengthOption/SeedLengthOption.tsx index 6647cf988d..ed600a677c 100644 --- a/src/app/templates/SeedPhraseInput/SeedLengthSelect/SeedLengthOption/SeedLengthOption.tsx +++ b/src/app/templates/SeedPhraseInput/SeedLengthSelect/SeedLengthOption/SeedLengthOption.tsx @@ -3,6 +3,9 @@ import React, { FC, memo, useCallback } from 'react'; import { emptyFn } from '@rnw-community/shared'; import classNames from 'clsx'; +import { ImportAccountSelectors } from 'app/pages/ImportAccount/selectors'; +import { setAnotherSelector, setTestID } from 'lib/analytics'; + import styles from './seedLengthOption.module.css'; interface Props { @@ -28,7 +31,12 @@ export const SeedLengthOption: FC = memo(({ option, selectedOption, onCli 'text-lg' )} > -