From f49e5076f3c0ba2c372148a5617949adc46f34fb Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Wed, 23 Feb 2022 17:00:26 -0330 Subject: [PATCH] Refactor: Extract SRP input from create vault component (#13720) This is a pure refactor that extracts the SRP input from the `CreateNewVault` component. This is intended to make future changes to the SRP input easier, and to reduce duplication between the old and new onboarding flows. Extensive unit tests have been added for the new SRP input component. A new test library was added (`@testing-library/user-event`) for simulating user events with components rendered using the `@testing-library` library. A new helper method has been added (`renderWithLocalization`) for rendering components using `@testing-library` with just our localization contexts added as a wrapper. The localization contexts were already added by the `renderWithProviders` helper function, but there is no need for a Redux provider in these unit tests. --- package.json | 1 + test/helpers/setup-helper.js | 8 + test/lib/render-helpers.js | 14 + ui/components/app/app-components.scss | 1 + .../app/create-new-vault/create-new-vault.js | 89 +-- .../create-new-vault/create-new-vault.scss | 23 - ui/components/app/srp-input/index.js | 1 + .../parse-secret-recovery-phrase'.test.js | 0 .../parse-secret-recovery-phrase.js | 0 ui/components/app/srp-input/srp-input.js | 112 ++++ ui/components/app/srp-input/srp-input.scss | 24 + .../app/srp-input/srp-input.stories.js | 23 + ui/components/app/srp-input/srp-input.test.js | 571 ++++++++++++++++++ yarn.lock | 7 + 14 files changed, 766 insertions(+), 108 deletions(-) create mode 100644 ui/components/app/srp-input/index.js rename ui/components/app/{create-new-vault => srp-input}/parse-secret-recovery-phrase'.test.js (100%) rename ui/components/app/{create-new-vault => srp-input}/parse-secret-recovery-phrase.js (100%) create mode 100644 ui/components/app/srp-input/srp-input.js create mode 100644 ui/components/app/srp-input/srp-input.scss create mode 100644 ui/components/app/srp-input/srp-input.stories.js create mode 100644 ui/components/app/srp-input/srp-input.test.js diff --git a/package.json b/package.json index ec8231202..754757ddb 100644 --- a/package.json +++ b/package.json @@ -262,6 +262,7 @@ "@testing-library/jest-dom": "^5.11.10", "@testing-library/react": "^10.4.8", "@testing-library/react-hooks": "^3.2.1", + "@testing-library/user-event": "^13.5.0", "@types/react": "^16.9.53", "addons-linter": "1.14.0", "babelify": "^10.0.0", diff --git a/test/helpers/setup-helper.js b/test/helpers/setup-helper.js index f9d2112aa..9d4b7d892 100644 --- a/test/helpers/setup-helper.js +++ b/test/helpers/setup-helper.js @@ -79,3 +79,11 @@ if (!window.crypto.getRandomValues) { // eslint-disable-next-line node/global-require window.crypto.getRandomValues = require('polyfill-crypto.getrandomvalues'); } + +// Used to test `clearClipboard` function +if (!window.navigator.clipboard) { + window.navigator.clipboard = {}; +} +if (!window.navigator.clipboard.writeText) { + window.navigator.clipboard.writeText = () => undefined; +} diff --git a/test/lib/render-helpers.js b/test/lib/render-helpers.js index 37c5d6370..9fc7aad16 100644 --- a/test/lib/render-helpers.js +++ b/test/lib/render-helpers.js @@ -95,3 +95,17 @@ export function renderWithProvider(component, store) { return render(component, { wrapper: Wrapper }); } + +export function renderWithLocalization(component) { + const Wrapper = ({ children }) => ( + + {children} + + ); + + Wrapper.propTypes = { + children: PropTypes.node, + }; + + return render(component, { wrapper: Wrapper }); +} diff --git a/ui/components/app/app-components.scss b/ui/components/app/app-components.scss index c11ff6027..a135c0766 100644 --- a/ui/components/app/app-components.scss +++ b/ui/components/app/app-components.scss @@ -54,6 +54,7 @@ @import 'selected-account/index'; @import 'signature-request/index'; @import 'signature-request-original/index'; +@import 'srp-input/srp-input'; @import 'tab-bar/index'; @import 'token-cell/token-cell'; @import 'token-list-display/token-list-display'; diff --git a/ui/components/app/create-new-vault/create-new-vault.js b/ui/components/app/create-new-vault/create-new-vault.js index 3c2b5007b..05ca7a716 100644 --- a/ui/components/app/create-new-vault/create-new-vault.js +++ b/ui/components/app/create-new-vault/create-new-vault.js @@ -1,17 +1,12 @@ -import { ethers } from 'ethers'; import React, { useCallback, useContext, useState } from 'react'; import PropTypes from 'prop-types'; import { useI18nContext } from '../../../hooks/useI18nContext'; import { MetaMetricsContext } from '../../../contexts/metametrics'; import TextField from '../../ui/text-field'; import Button from '../../ui/button'; -import { clearClipboard } from '../../../helpers/utils/util'; import CheckBox from '../../ui/check-box'; import Typography from '../../ui/typography'; -import { COLORS } from '../../../helpers/constants/design-system'; -import { parseSecretRecoveryPhrase } from './parse-secret-recovery-phrase'; - -const { isValidMnemonic } = ethers.utils; +import SrpInput from '../srp-input'; export default function CreateNewVault({ disabled = false, @@ -24,33 +19,11 @@ export default function CreateNewVault({ const [password, setPassword] = useState(''); const [passwordError, setPasswordError] = useState(''); const [seedPhrase, setSeedPhrase] = useState(''); - const [seedPhraseError, setSeedPhraseError] = useState(''); - const [showSeedPhrase, setShowSeedPhrase] = useState(false); const [termsChecked, setTermsChecked] = useState(false); const t = useI18nContext(); const metricsEvent = useContext(MetaMetricsContext); - const onSeedPhraseChange = useCallback( - (rawSeedPhrase) => { - let newSeedPhraseError = ''; - - if (rawSeedPhrase) { - const parsedSeedPhrase = parseSecretRecoveryPhrase(rawSeedPhrase); - const wordCount = parsedSeedPhrase.split(/\s/u).length; - if (wordCount % 3 !== 0 || wordCount > 24 || wordCount < 12) { - newSeedPhraseError = t('seedPhraseReq'); - } else if (!isValidMnemonic(parsedSeedPhrase)) { - newSeedPhraseError = t('invalidSeedPhrase'); - } - } - - setSeedPhrase(rawSeedPhrase); - setSeedPhraseError(newSeedPhraseError); - }, - [setSeedPhrase, setSeedPhraseError, t], - ); - const onPasswordChange = useCallback( (newPassword) => { let newConfirmPasswordError = ''; @@ -93,8 +66,7 @@ export default function CreateNewVault({ seedPhrase && (!includeTerms || termsChecked) && !passwordError && - !confirmPasswordError && - !seedPhraseError; + !confirmPasswordError; const onImport = useCallback( async (event) => { @@ -104,7 +76,7 @@ export default function CreateNewVault({ return; } - await onSubmit(password, parseSecretRecoveryPhrase(seedPhrase)); + await onSubmit(password, seedPhrase); }, [isValid, onSubmit, password, seedPhrase], ); @@ -121,10 +93,6 @@ export default function CreateNewVault({ setTermsChecked((currentTermsChecked) => !currentTermsChecked); }, [metricsEvent]); - const toggleShowSeedPhrase = useCallback(() => { - setShowSeedPhrase((currentShowSeedPhrase) => !currentShowSeedPhrase); - }, []); - const termsOfUse = t('acceptTermsOfUse', [
- - {showSeedPhrase ? ( -