1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-25 11:28:51 +01:00

Unit tests for first time flow/new account and onboarding flow. (#15625)

This commit is contained in:
Thomas Huang 2022-08-30 16:53:24 -07:00 committed by GitHub
parent 44d2f210d0
commit ece5901b40
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 474 additions and 13 deletions

View File

@ -75,7 +75,7 @@ export default function ExperimentalArea({ redirectTo }) {
}; };
return ( return (
<div className="experimental-area"> <div className="experimental-area" data-testid="experimental-area">
<div className="logo">{METAMASK_LOGO}</div> <div className="logo">{METAMASK_LOGO}</div>
<div className="experimental-text">{EXPERIMENTAL_AREA}</div> <div className="experimental-text">{EXPERIMENTAL_AREA}</div>
<div className="text"> <div className="text">

View File

@ -0,0 +1,106 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Name of the group should match snapshot 1`] = `
<div>
<div>
<div
class="first-time-flow__create-back"
>
<a
data-testid="onboarding-back-button"
href="#"
>
&lt; [back]
</a>
</div>
<div
class="first-time-flow__header"
>
[createPassword]
</div>
<form
class="first-time-flow__form"
>
<div
class="MuiFormControl-root MuiTextField-root first-time-flow__input MuiFormControl-marginNormal MuiFormControl-fullWidth"
>
<label
class="MuiFormLabel-root MuiInputLabel-root TextField-formLabel-9 TextField-largeInputLabel-13 MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-shrink Mui-focused Mui-focused TextField-formLabelFocused-10"
data-shrink="true"
for="create-password"
id="create-password-label"
>
[newPassword]
</label>
<div
class="MuiInputBase-root MuiInput-root TextField-inputRoot-12 MuiInputBase-fullWidth MuiInput-fullWidth Mui-focused Mui-focused TextField-inputFocused-11 MuiInputBase-formControl MuiInput-formControl"
>
<input
aria-invalid="false"
autocomplete="new-password"
class="MuiInputBase-input MuiInput-input"
data-testid="create-password"
dir="auto"
id="create-password"
type="password"
value=""
/>
</div>
</div>
<div
class="MuiFormControl-root MuiTextField-root first-time-flow__input MuiFormControl-marginNormal MuiFormControl-fullWidth"
>
<label
class="MuiFormLabel-root MuiInputLabel-root TextField-formLabel-9 TextField-largeInputLabel-13 MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-shrink"
data-shrink="true"
for="confirm-password"
id="confirm-password-label"
>
[confirmPassword]
</label>
<div
class="MuiInputBase-root MuiInput-root TextField-inputRoot-12 MuiInputBase-fullWidth MuiInput-fullWidth MuiInputBase-formControl MuiInput-formControl"
>
<input
aria-invalid="false"
autocomplete="confirm-password"
class="MuiInputBase-input MuiInput-input"
data-testid="confirm-password"
dir="auto"
id="confirm-password"
type="password"
value=""
/>
</div>
</div>
<div
class="first-time-flow__checkbox-container"
>
<div
aria-checked="false"
aria-labelledby="ftf-chk1-label"
class="first-time-flow__checkbox"
role="checkbox"
tabindex="0"
/>
<span
class="first-time-flow__checkbox-label"
id="ftf-chk1-label"
>
[acceptTermsOfUse]
</span>
</div>
<button
class="button btn--rounded btn-primary first-time-flow__button"
disabled=""
role="button"
tabindex="0"
>
[create]
</button>
</form>
</div>
</div>
`;

View File

@ -105,7 +105,6 @@ export default class NewAccount extends PureComponent {
event: EVENT_NAMES.ACCOUNT_PASSWORD_CREATED, event: EVENT_NAMES.ACCOUNT_PASSWORD_CREATED,
properties: {}, properties: {},
}); });
history.push(INITIALIZE_SEED_PHRASE_INTRO_ROUTE); history.push(INITIALIZE_SEED_PHRASE_INTRO_ROUTE);
} catch (error) { } catch (error) {
this.setState({ passwordError: error.message }); this.setState({ passwordError: error.message });
@ -138,6 +137,7 @@ export default class NewAccount extends PureComponent {
<div> <div>
<div className="first-time-flow__create-back"> <div className="first-time-flow__create-back">
<a <a
data-testid="onboarding-back-button"
onClick={(e) => { onClick={(e) => {
e.preventDefault(); e.preventDefault();
this.props.history.push(INITIALIZE_SELECT_ACTION_ROUTE); this.props.history.push(INITIALIZE_SELECT_ACTION_ROUTE);
@ -150,6 +150,7 @@ export default class NewAccount extends PureComponent {
<div className="first-time-flow__header">{t('createPassword')}</div> <div className="first-time-flow__header">{t('createPassword')}</div>
<form className="first-time-flow__form" onSubmit={this.handleCreate}> <form className="first-time-flow__form" onSubmit={this.handleCreate}>
<TextField <TextField
data-testid="create-password"
id="create-password" id="create-password"
label={t('newPassword')} label={t('newPassword')}
type="password" type="password"
@ -164,6 +165,7 @@ export default class NewAccount extends PureComponent {
largeLabel largeLabel
/> />
<TextField <TextField
data-testid="confirm-password"
id="confirm-password" id="confirm-password"
label={t('confirmPassword')} label={t('confirmPassword')}
type="password" type="password"

View File

@ -0,0 +1,108 @@
import React from 'react';
import { fireEvent, waitFor } from '@testing-library/react';
import {
INITIALIZE_SEED_PHRASE_INTRO_ROUTE,
INITIALIZE_SELECT_ACTION_ROUTE,
} from '../../../../helpers/constants/routes';
import { renderWithProvider } from '../../../../../test/lib/render-helpers';
import NewAccount from '.';
describe('Name of the group', () => {
const props = {
onSubmit: jest.fn(),
history: {
push: jest.fn(),
},
};
it('should match snapshot', () => {
const { container } = renderWithProvider(<NewAccount {...props} />);
expect(container).toMatchSnapshot();
});
it('should back button', () => {
const { queryByTestId } = renderWithProvider(<NewAccount {...props} />);
const onboardingBackButton = queryByTestId('onboarding-back-button');
fireEvent.click(onboardingBackButton);
expect(props.history.push).toHaveBeenCalledWith(
INITIALIZE_SELECT_ACTION_ROUTE,
);
});
it('should initialize with a disabled create button', () => {
const { queryByRole } = renderWithProvider(<NewAccount {...props} />);
const createButton = queryByRole('button', { type: 'primary' });
expect(createButton).toBeInTheDocument();
expect(createButton).toHaveAttribute('disabled');
});
it('should', async () => {
const { queryByRole, queryByTestId } = renderWithProvider(
<NewAccount {...props} />,
);
const password = 'a-new-password';
const checkTerms = queryByRole('checkbox');
const createPassword = queryByTestId('create-password');
const confirmPassword = queryByTestId('confirm-password');
const createButton = queryByRole('button', { type: 'primary' });
fireEvent.click(checkTerms);
fireEvent.change(createPassword, { target: { value: password } });
fireEvent.change(confirmPassword, { target: { value: password } });
expect(createButton).not.toHaveAttribute('disabled');
fireEvent.click(createButton);
await waitFor(() => {
expect(props.history.push).toHaveBeenCalledWith(
INITIALIZE_SEED_PHRASE_INTRO_ROUTE,
);
});
});
it('should error when the password and the confirm password are not the same', () => {
const { queryByRole, queryByTestId, queryByText } = renderWithProvider(
<NewAccount {...props} />,
);
const password = 'a-new-password';
const wrongPassword = 'wrong-password';
const createPassword = queryByTestId('create-password');
const confirmPassword = queryByTestId('confirm-password');
fireEvent.change(createPassword, { target: { value: password } });
fireEvent.change(confirmPassword, { target: { value: wrongPassword } });
const errorMessage = queryByText(/passwordsDontMatch/u);
expect(errorMessage).toBeInTheDocument();
// Create button is disabled.
const createButton = queryByRole('button', { type: 'primary' });
expect(createButton).toHaveAttribute('disabled');
});
it('should disable the create button if the terms are not checked but passwords are correct', () => {
const { queryByRole, queryByTestId } = renderWithProvider(
<NewAccount {...props} />,
);
const password = 'a-new-password';
const createPassword = queryByTestId('create-password');
const confirmPassword = queryByTestId('confirm-password');
fireEvent.change(createPassword, { target: { value: password } });
fireEvent.change(confirmPassword, { target: { value: password } });
const createButton = queryByRole('button', { type: 'primary' });
expect(createButton).toHaveAttribute('disabled');
});
});

View File

@ -151,7 +151,7 @@ export default function CreatePassword({
}; };
return ( return (
<div className="create-password__wrapper"> <div className="create-password__wrapper" data-testid="create-password">
{secretRecoveryPhrase && {secretRecoveryPhrase &&
firstTimeFlowType === FIRST_TIME_FLOW_TYPES.IMPORT ? ( firstTimeFlowType === FIRST_TIME_FLOW_TYPES.IMPORT ? (
<TwoStepProgressBar <TwoStepProgressBar

View File

@ -28,7 +28,7 @@ export default function CreationSuccessful() {
history.push(ONBOARDING_PIN_EXTENSION_ROUTE); history.push(ONBOARDING_PIN_EXTENSION_ROUTE);
}; };
return ( return (
<div className="creation-successful"> <div className="creation-successful" data-testid="creation-successful">
<Box textAlign={TEXT_ALIGN.CENTER}> <Box textAlign={TEXT_ALIGN.CENTER}>
<img src="./images/tada.png" /> <img src="./images/tada.png" />
<Typography <Typography

View File

@ -24,7 +24,7 @@ export default function ImportSRP({ submitSecretRecoveryPhrase }) {
const t = useI18nContext(); const t = useI18nContext();
return ( return (
<div className="import-srp"> <div className="import-srp" data-testid="import-srp">
<TwoStepProgressBar <TwoStepProgressBar
stage={twoStepStages.RECOVERY_PHRASE_CONFIRM} stage={twoStepStages.RECOVERY_PHRASE_CONFIRM}
marginBottom={4} marginBottom={4}

View File

@ -106,7 +106,10 @@ export default function OnboardingMetametrics() {
}; };
return ( return (
<div className="onboarding-metametrics"> <div
className="onboarding-metametrics"
data-testid="onboarding-metametrics"
>
<Typography <Typography
variant={TYPOGRAPHY.H2} variant={TYPOGRAPHY.H2}
align={TEXT_ALIGN.CENTER} align={TEXT_ALIGN.CENTER}

View File

@ -0,0 +1,236 @@
import { fireEvent, waitFor } from '@testing-library/react';
import React from 'react';
import configureMockStore from 'redux-mock-store';
import { renderWithProvider } from '../../../test/lib/render-helpers';
import {
///: BEGIN:ONLY_INCLUDE_IN(flask)
ONBOARDING_EXPERIMENTAL_AREA,
///: END:ONLY_INCLUDE_IN
ONBOARDING_CREATE_PASSWORD_ROUTE,
ONBOARDING_REVIEW_SRP_ROUTE,
ONBOARDING_CONFIRM_SRP_ROUTE,
ONBOARDING_UNLOCK_ROUTE,
ONBOARDING_WELCOME_ROUTE,
DEFAULT_ROUTE,
ONBOARDING_SECURE_YOUR_WALLET_ROUTE,
ONBOARDING_PRIVACY_SETTINGS_ROUTE,
ONBOARDING_COMPLETION_ROUTE,
ONBOARDING_IMPORT_WITH_SRP_ROUTE,
ONBOARDING_PIN_EXTENSION_ROUTE,
ONBOARDING_METAMETRICS,
} from '../../helpers/constants/routes';
import {
createNewVaultAndGetSeedPhrase,
unlockAndGetSeedPhrase,
} from '../../store/actions';
import OnboardingFlow from './onboarding-flow';
jest.mock('../../store/actions', () => ({
createNewVaultAndGetSeedPhrase: jest.fn().mockResolvedValue(null),
unlockAndGetSeedPhrase: jest.fn().mockResolvedValue(null),
createNewVaultAndRestore: jest.fn(),
}));
describe('Onboarding Flow', () => {
const mockState = {
metamask: {},
};
const store = configureMockStore()(mockState);
it('should route to the default route when completedOnboarding and seedPhraseBackedUp is true', () => {
const completedOnboardingState = {
metamask: {
completedOnboarding: true,
seedPhraseBackedUp: true,
},
};
const completedOnboardingStore = configureMockStore()(
completedOnboardingState,
);
const { history } = renderWithProvider(
<OnboardingFlow />,
completedOnboardingStore,
'/other',
);
expect(history.location.pathname).toStrictEqual(DEFAULT_ROUTE);
});
describe('Create Password', () => {
it('should render create password', () => {
const { queryByTestId } = renderWithProvider(
<OnboardingFlow />,
store,
ONBOARDING_CREATE_PASSWORD_ROUTE,
);
const createPassword = queryByTestId('create-password');
expect(createPassword).toBeInTheDocument();
});
it('should call createNewVaultAndGetSeedPhrase when creating a new wallet password', async () => {
const { queryByTestId } = renderWithProvider(
<OnboardingFlow />,
store,
ONBOARDING_CREATE_PASSWORD_ROUTE,
);
const password = 'a-new-password';
const checkTerms = queryByTestId('create-password-terms');
const createPassword = queryByTestId('create-password-new');
const confirmPassword = queryByTestId('create-password-confirm');
const createPasswordWallet = queryByTestId('create-password-wallet');
fireEvent.click(checkTerms);
fireEvent.change(createPassword, { target: { value: password } });
fireEvent.change(confirmPassword, { target: { value: password } });
fireEvent.click(createPasswordWallet);
await waitFor(() =>
expect(createNewVaultAndGetSeedPhrase).toHaveBeenCalled(),
);
});
});
it('should render secure your wallet component', () => {
const { queryByTestId } = renderWithProvider(
<OnboardingFlow />,
store,
ONBOARDING_SECURE_YOUR_WALLET_ROUTE,
);
const secureYourWallet = queryByTestId('secure-your-wallet');
expect(secureYourWallet).toBeInTheDocument();
});
it('should render review recovery phrase', () => {
const { queryByTestId } = renderWithProvider(
<OnboardingFlow />,
store,
ONBOARDING_REVIEW_SRP_ROUTE,
);
const recoveryPhrase = queryByTestId('recovery-phrase');
expect(recoveryPhrase).toBeInTheDocument();
});
it('should render confirm recovery phrase', () => {
const { queryByTestId } = renderWithProvider(
<OnboardingFlow />,
store,
ONBOARDING_CONFIRM_SRP_ROUTE,
);
const confirmRecoveryPhrase = queryByTestId('confirm-recovery-phrase');
expect(confirmRecoveryPhrase).toBeInTheDocument();
});
it('should render import seed phrase', () => {
const { queryByTestId } = renderWithProvider(
<OnboardingFlow />,
store,
ONBOARDING_IMPORT_WITH_SRP_ROUTE,
);
const importSrp = queryByTestId('import-srp');
expect(importSrp).toBeInTheDocument();
});
describe('Unlock Screen', () => {
it('should render unlock page', () => {
const { queryByTestId } = renderWithProvider(
<OnboardingFlow />,
store,
ONBOARDING_UNLOCK_ROUTE,
);
const unlockPage = queryByTestId('unlock-page');
expect(unlockPage).toBeInTheDocument();
});
it('should', async () => {
const { getByLabelText, getByText } = renderWithProvider(
<OnboardingFlow />,
store,
ONBOARDING_UNLOCK_ROUTE,
);
const password = 'a-new-password';
const inputPassword = getByLabelText('Password');
const unlockButton = getByText('Unlock');
fireEvent.change(inputPassword, { target: { value: password } });
fireEvent.click(unlockButton);
await waitFor(() => expect(unlockAndGetSeedPhrase).toHaveBeenCalled());
});
});
it('should render privacy settings', () => {
const { queryByTestId } = renderWithProvider(
<OnboardingFlow />,
store,
ONBOARDING_PRIVACY_SETTINGS_ROUTE,
);
const privacySettings = queryByTestId('privacy-settings');
expect(privacySettings).toBeInTheDocument();
});
it('should render onboarding creation/completion successful', () => {
const { queryByTestId } = renderWithProvider(
<OnboardingFlow />,
store,
ONBOARDING_COMPLETION_ROUTE,
);
const creationSuccessful = queryByTestId('creation-successful');
expect(creationSuccessful).toBeInTheDocument();
});
it('should render onboarding welcome screen', () => {
const { queryByTestId } = renderWithProvider(
<OnboardingFlow />,
store,
ONBOARDING_WELCOME_ROUTE,
);
const onboardingWelcome = queryByTestId('onboarding-welcome');
expect(onboardingWelcome).toBeInTheDocument();
});
it('should render onboarding pin extension screen', () => {
const { queryByTestId } = renderWithProvider(
<OnboardingFlow />,
store,
ONBOARDING_PIN_EXTENSION_ROUTE,
);
const pinExtension = queryByTestId('onboarding-pin-extension');
expect(pinExtension).toBeInTheDocument();
});
it('should render onboarding metametrics screen', () => {
const { queryByTestId } = renderWithProvider(
<OnboardingFlow />,
store,
ONBOARDING_METAMETRICS,
);
const onboardingMetametrics = queryByTestId('onboarding-metametrics');
expect(onboardingMetametrics).toBeInTheDocument();
});
it('should render onboarding experimental screen', () => {
const { queryByTestId } = renderWithProvider(
<OnboardingFlow />,
store,
ONBOARDING_EXPERIMENTAL_AREA,
);
const onboardingMetametrics = queryByTestId('experimental-area');
expect(onboardingMetametrics).toBeInTheDocument();
});
});

View File

@ -19,7 +19,10 @@ export default function OnboardingPinExtension() {
const history = useHistory(); const history = useHistory();
return ( return (
<div className="onboarding-pin-extension"> <div
className="onboarding-pin-extension"
data-testid="onboarding-pin-extension"
>
<Typography <Typography
variant={TYPOGRAPHY.H2} variant={TYPOGRAPHY.H2}
align={TEXT_ALIGN.CENTER} align={TEXT_ALIGN.CENTER}

View File

@ -39,7 +39,7 @@ export default function PrivacySettings() {
return ( return (
<> <>
<div className="privacy-settings"> <div className="privacy-settings" data-testid="privacy-settings">
<div className="privacy-settings__header"> <div className="privacy-settings__header">
<Typography variant={TYPOGRAPHY.H2} fontWeight={FONT_WEIGHT.BOLD}> <Typography variant={TYPOGRAPHY.H2} fontWeight={FONT_WEIGHT.BOLD}>
{t('setAdvancedPrivacySettings')} {t('setAdvancedPrivacySettings')}

View File

@ -54,7 +54,10 @@ export default function ConfirmRecoveryPhrase({ secretRecoveryPhrase = '' }) {
}; };
return ( return (
<div className="recovery-phrase__confirm"> <div
className="recovery-phrase__confirm"
data-testid="confirm-recovery-phrase"
>
<ThreeStepProgressBar <ThreeStepProgressBar
stage={threeStepStages.RECOVERY_PHRASE_CONFIRM} stage={threeStepStages.RECOVERY_PHRASE_CONFIRM}
marginBottom={4} marginBottom={4}

View File

@ -28,7 +28,7 @@ export default function RecoveryPhrase({ secretRecoveryPhrase }) {
const [hiddenPhrase, setHiddenPhrase] = useState(false); const [hiddenPhrase, setHiddenPhrase] = useState(false);
return ( return (
<div className="recovery-phrase"> <div className="recovery-phrase" data-testid="recovery-phrase">
<ThreeStepProgressBar stage={threeStepStages.RECOVERY_PHRASE_REVIEW} /> <ThreeStepProgressBar stage={threeStepStages.RECOVERY_PHRASE_REVIEW} />
<Box <Box
justifyContent={JUSTIFY_CONTENT.CENTER} justifyContent={JUSTIFY_CONTENT.CENTER}

View File

@ -55,7 +55,7 @@ export default function SecureYourWallet() {
const defaultLang = subtitles[currentLocale] ? currentLocale : 'en'; const defaultLang = subtitles[currentLocale] ? currentLocale : 'en';
return ( return (
<div className="secure-your-wallet"> <div className="secure-your-wallet" data-testid="secure-your-wallet">
{showSkipSRPBackupPopover && ( {showSkipSRPBackupPopover && (
<SkipSRPBackup handleClose={() => setShowSkipSRPBackupPopover(false)} /> <SkipSRPBackup handleClose={() => setShowSkipSRPBackupPopover(false)} />
)} )}

View File

@ -32,7 +32,7 @@ export default function OnboardingWelcome() {
}; };
return ( return (
<div className="onboarding-welcome"> <div className="onboarding-welcome" data-testid="onboarding-welcome">
<Carousel showThumbs={false} showStatus={false} showArrows> <Carousel showThumbs={false} showStatus={false} showArrows>
<div> <div>
<Typography <Typography

View File

@ -168,7 +168,7 @@ export default class UnlockPage extends Component {
return ( return (
<div className="unlock-page__container"> <div className="unlock-page__container">
<div className="unlock-page"> <div className="unlock-page" data-testid="unlock-page">
<div className="unlock-page__mascot-container"> <div className="unlock-page__mascot-container">
<Mascot <Mascot
animationEventEmitter={this.animationEventEmitter} animationEventEmitter={this.animationEventEmitter}