1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 01:39:44 +01:00

Create Password onboarding unit test, test-ids, and snapshot (#18257)

* Create Password onboarding unit test, test-ids, and snapshot

* Add button inline snapshot check for import wallet text

* Don't adjust inlineSnapshot formatting

* Get text content

---------

Co-authored-by: Brad Decker <bhdecker84@gmail.com>
This commit is contained in:
Thomas Huang 2023-04-20 13:33:50 -05:00 committed by GitHub
parent b91043cf72
commit 8d29fc907d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 577 additions and 1 deletions

View File

@ -0,0 +1,172 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Onboarding Create Password Render should match snapshot 1`] = `
<div>
<div
class="create-password__wrapper"
data-testid="create-password"
>
<div
class="box box--margin-bottom-4 box--flex-direction-row"
>
<ul
class="progressbar"
>
<li
class="active"
>
Create password
</li>
<li
class=""
>
Secure wallet
</li>
<li
class=""
>
Confirm secret recovery phrase
</li>
</ul>
</div>
<h2
class="box box--margin-top-1 box--margin-bottom-1 box--flex-direction-row typography typography--h2 typography--weight-bold typography--style-normal typography--color-text-default"
>
Create password
</h2>
<h4
class="box box--margin-top-1 box--margin-bottom-1 box--flex-direction-row typography typography--h4 typography--weight-normal typography--style-normal typography--align-center typography--color-text-default"
>
This password will unlock your MetaMask wallet only on this device. MetaMask can not recover this password.
</h4>
<div
class="box box--margin-top-3 box--flex-direction-row box--justify-content-center box--display-flex"
>
<form
class="create-password__form"
>
<div
class="form-field"
>
<label
class="box box--flex-direction-row"
>
<div
class="form-field__heading"
>
<div
class="box form-field__heading-title box--display-flex box--flex-direction-row box--align-items-baseline"
>
<h6
class="box box--margin-top-1 box--margin-bottom-1 box--display-inline-block box--flex-direction-row typography typography--h6 typography--weight-bold typography--style-normal typography--color-text-default"
>
New password (8 characters min)
</h6>
</div>
<div
class="box form-field__heading-detail box--margin-right-2 box--flex-direction-row box--text-align-end"
>
<h6
class="box box--margin-top-1 box--margin-bottom-1 box--flex-direction-row typography typography--h7 typography--weight-normal typography--style-normal typography--color-text-default"
>
<a
class="create-password__form--password-button"
data-testid="show-password"
href=""
>
Show
</a>
</h6>
</div>
</div>
<input
class="form-field__input"
data-testid="create-password-new"
type="password"
value=""
/>
</label>
</div>
<div
class="form-field"
>
<label
class="box box--flex-direction-row"
>
<div
class="form-field__heading"
>
<div
class="box form-field__heading-title box--display-flex box--flex-direction-row box--align-items-baseline"
>
<h6
class="box box--margin-top-1 box--margin-bottom-1 box--display-inline-block box--flex-direction-row typography typography--h6 typography--weight-bold typography--style-normal typography--color-text-default"
>
Confirm password
</h6>
</div>
</div>
<input
class="form-field__input"
data-testid="create-password-confirm"
type="password"
value=""
/>
</label>
</div>
<div
class="box box--margin-bottom-4 box--flex-direction-row box--justify-content-space-between box--align-items-center box--display-flex"
>
<label
class="create-password__form__terms-label"
>
<input
class="check-box far fa-square"
data-testid="create-password-terms"
readonly=""
type="checkbox"
/>
<h5
class="box box--margin-top-1 box--margin-bottom-1 box--margin-left-3 box--flex-direction-row typography typography--h5 typography--weight-normal typography--style-normal typography--color-text-default"
>
<span>
I understand that MetaMask cannot recover this password for me.
<a
href="https://metamask.zendesk.com/hc/en-us/articles/4404722782107"
rel="noopener noreferrer"
target="_blank"
>
<span
class="create-password__link-text"
>
Learn more
</span>
</a>
</span>
</h5>
</label>
</div>
<button
class="button btn--rounded btn-primary btn--large create-password__form--submit-button"
data-testid="create-password-wallet"
disabled=""
role="button"
tabindex="0"
>
Create a new wallet
</button>
</form>
</div>
</div>
</div>
`;

View File

@ -85,6 +85,7 @@ export default function CreatePassword({
if (isTooShort) {
return {
className: 'create-password__weak',
dataTestId: 'short-password-error',
text: t('passwordNotLongEnough'),
description: '',
};
@ -92,6 +93,7 @@ export default function CreatePassword({
if (score >= 4) {
return {
className: 'create-password__strong',
dataTestId: 'strong-password',
text: t('strong'),
description: '',
};
@ -99,12 +101,14 @@ export default function CreatePassword({
if (score === 3) {
return {
className: 'create-password__average',
dataTestId: 'average-password',
text: t('average'),
description: t('passwordStrengthDescription'),
};
}
return {
className: 'create-password__weak',
dataTestId: 'weak-password',
text: t('weak'),
description: t('passwordStrengthDescription'),
};
@ -116,7 +120,11 @@ export default function CreatePassword({
const { score } = zxcvbn(passwordInput);
const passwordStrengthLabel = getPasswordStrengthLabel(isTooShort, score);
const passwordStrengthComponent = t('passwordStrength', [
<span key={score} className={passwordStrengthLabel.className}>
<span
key={score}
data-testid={passwordStrengthLabel.dataTestId}
className={passwordStrengthLabel.className}
>
{passwordStrengthLabel.text}
</span>,
]);
@ -206,6 +214,7 @@ export default function CreatePassword({
<Typography variant={TypographyVariant.H7}>
<a
href=""
data-testid="show-password"
className="create-password__form--password-button"
onClick={(e) => {
e.preventDefault();

View File

@ -0,0 +1,395 @@
import React from 'react';
import { fireEvent, waitFor } from '@testing-library/react';
import configureMockStore from 'redux-mock-store';
import { renderWithProvider } from '../../../../test/lib/render-helpers';
import initializedMockState from '../../../../test/data/mock-send-state.json';
import {
ONBOARDING_SECURE_YOUR_WALLET_ROUTE,
ONBOARDING_COMPLETION_ROUTE,
} from '../../../helpers/constants/routes';
import { FIRST_TIME_FLOW_TYPES } from '../../../helpers/constants/onboarding';
import CreatePassword from './create-password';
const mockHistoryPush = jest.fn();
const mockHistoryReplace = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useHistory: () => ({
push: mockHistoryPush,
replace: mockHistoryReplace,
}),
}));
describe('Onboarding Create Password', () => {
const mockState = {
metamask: {
identities: {},
selectedAddress: '',
},
};
const mockCreateNewAccount = jest.fn().mockResolvedValue();
afterEach(() => {
jest.clearAllMocks();
});
describe('Initialized State Conditionals with keyrings and firstTimeFlowType', () => {
it('should route to secure your wallet when keyring is present but not imported first time flow type', () => {
const mockStore = configureMockStore()(initializedMockState);
renderWithProvider(<CreatePassword />, mockStore);
expect(mockHistoryReplace).toHaveBeenCalledWith(
ONBOARDING_SECURE_YOUR_WALLET_ROUTE,
);
});
it('should route to completion when keyring is present and imported first time flow type', () => {
const importFirstTimeFlowState = {
...initializedMockState,
metamask: {
...initializedMockState.metamask,
firstTimeFlowType: 'import',
},
};
const mockStore = configureMockStore()(importFirstTimeFlowState);
renderWithProvider(<CreatePassword />, mockStore);
expect(mockHistoryReplace).toHaveBeenCalledWith(
ONBOARDING_COMPLETION_ROUTE,
);
});
});
describe('Render', () => {
it('should match snapshot', () => {
const mockStore = configureMockStore()(mockState);
const { container } = renderWithProvider(<CreatePassword />, mockStore);
expect(container).toMatchSnapshot();
});
});
describe('Password Validation Checks', () => {
it('should show password as text when click Show under password', () => {
const mockStore = configureMockStore()(mockState);
const { queryByTestId } = renderWithProvider(
<CreatePassword />,
mockStore,
);
const createPassword = queryByTestId('create-password-new');
const event = {
target: {
value: '1234567',
},
};
fireEvent.change(createPassword, event);
expect(createPassword).toHaveAttribute('type', 'password');
const showPassword = queryByTestId('show-password');
fireEvent.click(showPassword);
expect(createPassword).toHaveAttribute('type', 'text');
});
it('should disable create new account button and show short password error with password length of 7', () => {
const mockStore = configureMockStore()(mockState);
const { queryByTestId } = renderWithProvider(
<CreatePassword createNewAccount={mockCreateNewAccount} />,
mockStore,
);
const createPassword = queryByTestId('create-password-new');
const event = {
target: {
value: '1234567',
},
};
fireEvent.change(createPassword, event);
const shortPasswordError = queryByTestId('short-password-error');
expect(shortPasswordError).toBeInTheDocument();
const createNewWalletButton = queryByTestId('create-password-wallet');
expect(createNewWalletButton).toBeDisabled();
fireEvent.click(createNewWalletButton);
expect(mockCreateNewAccount).not.toHaveBeenCalled();
});
it('should show weak password strength', () => {
const mockStore = configureMockStore()(mockState);
const { queryByTestId } = renderWithProvider(
<CreatePassword createNewAccount={mockCreateNewAccount} />,
mockStore,
);
const createNewWalletButton = queryByTestId('create-password-wallet');
const createPassword = queryByTestId('create-password-new');
const event = {
target: {
value: '12345678',
},
};
fireEvent.change(createPassword, event);
const weakPasswordError = queryByTestId('weak-password');
expect(weakPasswordError).toBeInTheDocument();
expect(createNewWalletButton).toBeDisabled();
fireEvent.click(createNewWalletButton);
expect(mockCreateNewAccount).not.toHaveBeenCalled();
});
it('should show average password strength', () => {
const mockStore = configureMockStore()(mockState);
const { queryByTestId } = renderWithProvider(
<CreatePassword createNewAccount={mockCreateNewAccount} />,
mockStore,
);
const createNewWalletButton = queryByTestId('create-password-wallet');
const createPassword = queryByTestId('create-password-new');
const event = {
target: {
value: 'ZsE(!6679',
},
};
fireEvent.change(createPassword, event);
const weakPasswordError = queryByTestId('average-password');
expect(weakPasswordError).toBeInTheDocument();
expect(createNewWalletButton).toBeDisabled();
fireEvent.click(createNewWalletButton);
expect(mockCreateNewAccount).not.toHaveBeenCalled();
});
it('should show strong password strength', () => {
const mockStore = configureMockStore()(mockState);
const { queryByTestId } = renderWithProvider(
<CreatePassword createNewAccount={mockCreateNewAccount} />,
mockStore,
);
const createPassword = queryByTestId('create-password-new');
const event = {
target: {
value: 'E}URkDoV|/*,pxI',
},
};
fireEvent.change(createPassword, event);
const weakPasswordError = queryByTestId('strong-password');
expect(weakPasswordError).toBeInTheDocument();
const createNewWalletButton = queryByTestId('create-password-wallet');
expect(createNewWalletButton).toBeDisabled();
fireEvent.click(createNewWalletButton);
expect(mockCreateNewAccount).not.toHaveBeenCalled();
});
it('should show mismatch password error', () => {
const mockStore = configureMockStore()(mockState);
const { queryByTestId, queryByText } = renderWithProvider(
<CreatePassword createNewAccount={mockCreateNewAccount} />,
mockStore,
);
const createPassword = queryByTestId('create-password-new');
const confirmPassword = queryByTestId('create-password-confirm');
const createPasswordEvent = {
target: {
value: '123456789',
},
};
const confirmPasswordEvent = {
target: {
value: '12345678',
},
};
fireEvent.change(createPassword, createPasswordEvent);
fireEvent.change(confirmPassword, confirmPasswordEvent);
const passwordMismatchError = queryByText("Passwords don't match");
expect(passwordMismatchError).toBeInTheDocument();
const createNewWalletButton = queryByTestId('create-password-wallet');
expect(createNewWalletButton).toBeDisabled();
fireEvent.click(createNewWalletButton);
expect(mockCreateNewAccount).not.toHaveBeenCalled();
});
it('should not create new wallet without terms checked', () => {
const mockStore = configureMockStore()(mockState);
const { queryByTestId } = renderWithProvider(
<CreatePassword createNewAccount={mockCreateNewAccount} />,
mockStore,
);
const createPassword = queryByTestId('create-password-new');
const confirmPassword = queryByTestId('create-password-confirm');
const createPasswordEvent = {
target: {
value: '12345678',
},
};
const confirmPasswordEvent = {
target: {
value: '12345678',
},
};
fireEvent.change(createPassword, createPasswordEvent);
fireEvent.change(confirmPassword, confirmPasswordEvent);
const terms = queryByTestId('create-password-terms');
expect(terms).not.toBeChecked();
const createNewWalletButton = queryByTestId('create-password-wallet');
expect(createNewWalletButton).toBeDisabled();
fireEvent.click(createNewWalletButton);
expect(mockCreateNewAccount).not.toHaveBeenCalled();
});
});
describe('Create New Account', () => {
it('should create new account with correct passwords and terms checked', async () => {
const mockStore = configureMockStore()(mockState);
const { queryByTestId } = renderWithProvider(
<CreatePassword createNewAccount={mockCreateNewAccount} />,
mockStore,
);
const createPassword = queryByTestId('create-password-new');
const confirmPassword = queryByTestId('create-password-confirm');
const password = '12345678';
const createPasswordEvent = {
target: {
value: password,
},
};
const confirmPasswordEvent = {
target: {
value: password,
},
};
fireEvent.change(createPassword, createPasswordEvent);
fireEvent.change(confirmPassword, confirmPasswordEvent);
const terms = queryByTestId('create-password-terms');
fireEvent.click(terms);
const createNewWalletButton = queryByTestId('create-password-wallet');
expect(createNewWalletButton).not.toBeDisabled();
fireEvent.click(createNewWalletButton);
expect(mockCreateNewAccount).toHaveBeenCalledWith(password);
await waitFor(() => {
expect(mockHistoryPush).toHaveBeenCalledWith(
ONBOARDING_SECURE_YOUR_WALLET_ROUTE,
);
});
});
});
describe('Import Wallet', () => {
const importMockState = {
...mockState,
metamask: {
...mockState.metamask,
firstTimeFlowType: FIRST_TIME_FLOW_TYPES.IMPORT,
},
};
it('should import wallet', async () => {
const mockStore = configureMockStore()(importMockState);
const props = {
importWithRecoveryPhrase: jest.fn().mockResolvedValue(),
secretRecoveryPhrase: 'SRP',
};
const { queryByTestId } = renderWithProvider(
<CreatePassword {...props} />,
mockStore,
);
const createPassword = queryByTestId('create-password-new');
const confirmPassword = queryByTestId('create-password-confirm');
const password = '12345678';
const createPasswordEvent = {
target: {
value: password,
},
};
const confirmPasswordEvent = {
target: {
value: password,
},
};
fireEvent.change(createPassword, createPasswordEvent);
fireEvent.change(confirmPassword, confirmPasswordEvent);
const terms = queryByTestId('create-password-terms');
fireEvent.click(terms);
const importWalletButton = queryByTestId('create-password-import');
expect(importWalletButton.textContent).toMatchInlineSnapshot(
`"Import my wallet"`,
);
fireEvent.click(importWalletButton);
expect(props.importWithRecoveryPhrase).toHaveBeenCalledWith(
password,
props.secretRecoveryPhrase,
);
await waitFor(() => {
expect(mockHistoryPush).toHaveBeenCalledWith(
ONBOARDING_COMPLETION_ROUTE,
);
});
});
});
});