1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-22 09:57:02 +01:00

Unit tests for various modals (#18115)

* Unit tests for Hide Token Confirmation modal

* Unit test for Export Private Key modal

* Unit test for Customize Nonce modal

* Bump coverage targets

---------

Co-authored-by: Brad Decker <bhdecker84@gmail.com>
This commit is contained in:
Thomas Huang 2023-04-24 09:55:32 -07:00 committed by GitHub
parent 6f2a5faaea
commit e65b955b19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 632 additions and 0 deletions

View File

@ -0,0 +1,119 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Customize Nonce should match snapshot 1`] = `
<div>
<div
class="modal-container customize-nonce-modal-container"
>
<div
class="modal-container__content customize-nonce-modal-content"
>
<div
class="customize-nonce-modal"
>
<div
class="customize-nonce-modal__main-header"
>
<h4
class="box box--margin-top-1 box--margin-bottom-1 box--flex-direction-row typography customize-nonce-modal__main-title typography--h4 typography--weight-bold typography--style-normal typography--color-text-default"
>
Edit nonce
</h4>
<button
aria-label="Close"
class="box mm-button-icon mm-button-icon--size-sm customize-nonce-modal__close box--display-inline-flex box--flex-direction-row box--justify-content-center box--align-items-center box--color-icon-default box--background-color-transparent box--rounded-lg"
>
<span
class="box mm-icon mm-icon--size-sm box--display-inline-block box--flex-direction-row box--color-inherit"
style="mask-image: url('./images/icons/close.svg');"
/>
</button>
</div>
<div
class="box box--margin-top-2 box--display-inline-flex box--flex-direction-row box--align-items-center"
>
<h6
class="box box--margin-top-1 box--margin-bottom-1 box--flex-direction-row typography typography--h6 typography--weight-normal typography--style-normal typography--color-text-default"
>
This is an advanced feature, use cautiously.
<a
class="button btn-link customize-nonce-modal__link"
href="https://metamask.zendesk.com/hc/en-us/articles/7417499333531-How-to-customize-a-transaction-nonce"
rel="noopener noreferrer"
target="_blank"
>
Learn more
</a>
</h6>
</div>
<div
class="box box--margin-top-3 box--flex-direction-row"
>
<div
class="box box--display-flex box--flex-direction-row box--align-items-center"
>
<h6
class="box box--margin-top-1 box--margin-bottom-1 box--flex-direction-row box--width-5/6 typography typography--h6 typography--weight-bold typography--style-normal typography--color-text-default"
>
Edit nonce
</h6>
<div
class="box box--flex-direction-row box--width-1/6"
>
<a
class="button btn-link customize-nonce-modal__reset"
data-testid="customize-nonce-reset"
role="button"
tabindex="0"
>
Reset
</a>
</div>
</div>
<div
class="customize-nonce-modal__input"
>
<div
class="MuiFormControl-root MuiTextField-root MuiFormControl-marginDense MuiFormControl-fullWidth"
>
<div
class="MuiInputBase-root MuiInput-root TextField-inputRoot-12 MuiInputBase-fullWidth MuiInput-fullWidth MuiInputBase-formControl MuiInput-formControl MuiInputBase-marginDense MuiInput-marginDense"
>
<input
aria-invalid="false"
class="MuiInputBase-input MuiInput-input MuiInputBase-inputMarginDense MuiInput-inputMarginDense"
data-testid="custom-nonce-input"
dir="auto"
id="custom-nonce-id"
min="0"
placeholder="1"
type="number"
value=""
/>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="modal-container__footer"
>
<button
class="button btn--rounded btn-secondary modal-container__footer-button"
role="button"
tabindex="0"
>
Cancel
</button>
<button
class="button btn--rounded btn-primary modal-container__footer-button"
role="button"
tabindex="0"
>
Save
</button>
</div>
</div>
</div>
`;

View File

@ -99,6 +99,7 @@ const CustomizeNonce = ({
<Button
type="link"
className="customize-nonce-modal__reset"
data-testid="customize-nonce-reset"
onClick={() => {
setCustomNonce(nextNonce);
}}
@ -110,6 +111,7 @@ const CustomizeNonce = ({
<div className="customize-nonce-modal__input">
<TextField
type="number"
data-testid="custom-nonce-input"
min="0"
placeholder={
customNonceValue ||

View File

@ -0,0 +1,132 @@
import React from 'react';
import { fireEvent } from '@testing-library/react';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { renderWithProvider } from '../../../../../test/lib/render-helpers';
import CustomizeNonce from '.';
const mockHideModal = jest.fn();
jest.mock('../../../../store/actions.ts', () => ({
...jest.requireActual('../../../../store/actions.ts'),
hideModal: () => mockHideModal,
}));
describe('Customize Nonce', () => {
const mockState = {
appState: {
modal: {
modalState: {
props: {},
},
},
},
};
const mockStore = configureMockStore([thunk])(mockState);
const props = {
nextNonce: 1,
customNonceValue: '',
updateCustomNonce: jest.fn(),
getNextNonce: jest.fn(),
};
afterEach(() => {
jest.clearAllMocks();
});
it('should match snapshot', () => {
const { container } = renderWithProvider(
<CustomizeNonce {...props} />,
mockStore,
);
expect(container).toMatchSnapshot();
});
it('should change and submit custom nonce', async () => {
const { queryByTestId, queryByText } = renderWithProvider(
<CustomizeNonce {...props} />,
mockStore,
);
const nonceInputEvent = {
target: {
value: 101,
},
};
const nonceInput = queryByTestId('custom-nonce-input');
fireEvent.change(nonceInput, nonceInputEvent);
expect(nonceInput).toHaveValue(101);
const saveButton = queryByText('Save');
fireEvent.click(saveButton);
expect(props.updateCustomNonce).toHaveBeenCalledWith('101');
expect(props.getNextNonce).toHaveBeenCalled();
expect(mockHideModal).toHaveBeenCalled();
});
it('should handle emptry string custom nonce', () => {
const { queryByTestId, queryByText } = renderWithProvider(
<CustomizeNonce {...props} />,
mockStore,
);
const nonceInputEvent = {
target: {
value: '',
},
};
const nonceInput = queryByTestId('custom-nonce-input');
fireEvent.change(nonceInput, nonceInputEvent);
const saveButton = queryByText('Save');
fireEvent.click(saveButton);
expect(props.updateCustomNonce).toHaveBeenCalledWith(
props.customNonceValue,
);
});
it('should handle cancel', async () => {
const { queryByText } = renderWithProvider(
<CustomizeNonce {...props} />,
mockStore,
);
const modalClose = queryByText('Cancel');
fireEvent.click(modalClose);
expect(mockHideModal).toHaveBeenCalled();
});
it('should handle reset of nonce', async () => {
const { queryByTestId } = renderWithProvider(
<CustomizeNonce {...props} />,
mockStore,
);
const resetNonce = queryByTestId('customize-nonce-reset');
const nonceInputEvent = {
target: {
value: 101,
},
};
const nonceInput = queryByTestId('custom-nonce-input');
fireEvent.change(nonceInput, nonceInputEvent);
expect(nonceInput).toHaveValue(101);
fireEvent.click(resetNonce);
expect(nonceInput).toHaveValue(props.nextNonce);
});
});

View File

@ -0,0 +1,120 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Export PrivateKey Modal should match snapshot 1`] = `
<div>
<div
class="export-private-key-modal account-modal"
style="border-radius: 4px;"
>
<div
class="account-modal__container"
>
<div>
<div
class=""
>
<div
class="identicon"
style="height: 64px; width: 64px; border-radius: 32px;"
>
<div
style="border-radius: 50px; overflow: hidden; padding: 0px; margin: 0px; width: 64px; height: 64px; display: inline-block; background: rgb(250, 58, 0);"
>
<svg
height="64"
width="64"
x="0"
y="0"
>
<rect
fill="#18CDF2"
height="64"
transform="translate(-2.09678700758788 -6.608568138920997) rotate(328.9 32 32)"
width="64"
x="0"
y="0"
/>
<rect
fill="#035E56"
height="64"
transform="translate(-36.59692341766409 21.1849237434972) rotate(176.2 32 32)"
width="64"
x="0"
y="0"
/>
<rect
fill="#F26602"
height="64"
transform="translate(33.335684036447844 -28.410279445994163) rotate(468.9 32 32)"
width="64"
x="0"
y="0"
/>
</svg>
</div>
</div>
</div>
</div>
<button
class="account-modal__close"
/>
<span
class="export-private-key-modal__account-name"
>
Test Account
</span>
<div
class="ellip-address-wrapper"
>
0x0DCD5D886577d5081B0c52e242Ef29E70Be3E7bc
</div>
<div
class="export-private-key-modal__divider"
/>
<span
class="export-private-key-modal__body-title"
>
Show Private Keys
</span>
<div
class="export-private-key-modal__password"
>
<span
class="export-private-key-modal__password-label"
>
Type your MetaMask password
</span>
<input
class="export-private-key-modal__password-input"
data-testid="password-input"
type="password"
/>
</div>
<div
class="export-private-key-modal__password--warning"
>
Warning: Never disclose this key. Anyone with your private keys can steal any assets held in your account.
</div>
<div
class="export-private-key-modal__buttons"
>
<button
class="button btn--rounded btn-secondary btn--large export-private-key-modal__button export-private-key-modal__button--cancel"
role="button"
tabindex="0"
>
Cancel
</button>
<button
class="button btn--rounded btn-primary btn--large export-private-key-modal__button"
disabled=""
role="button"
tabindex="0"
>
Confirm
</button>
</div>
</div>
</div>
</div>
`;

View File

@ -98,6 +98,7 @@ export default class ExportPrivateKeyModal extends Component {
<input
type="password"
className="export-private-key-modal__password-input"
data-testid="password-input"
onChange={(event) => this.setState({ password: event.target.value })}
/>
);

View File

@ -0,0 +1,81 @@
import React from 'react';
import { fireEvent } from '@testing-library/react';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { renderWithProvider } from '../../../../../test/lib/render-helpers';
import mockState from '../../../../../test/data/mock-state.json';
import * as actions from '../../../../store/actions';
import ExportPrivateKeyModal from '.';
jest.mock('../../../../store/actions.ts', () => ({
...jest.requireActual('../../../../store/actions.ts'),
exportAccount: jest.fn().mockReturnValue(jest.fn().mockResolvedValueOnce()),
hideWarning: () => jest.fn(),
showModal: () => jest.fn(),
hideModal: () => jest.fn(),
clearAccountDetails: () => jest.fn(),
}));
describe('Export PrivateKey Modal', () => {
const password = 'a-password';
const privKeyModalState = {
...mockState,
appState: {
...mockState.appState,
accountDetail: {
privateKey: '0xPrivKey',
},
},
};
const mockStore = configureMockStore([thunk])(privKeyModalState);
afterEach(() => {
jest.clearAllMocks();
});
it('should match snapshot', () => {
const { container } = renderWithProvider(
<ExportPrivateKeyModal />,
mockStore,
);
expect(container).toMatchSnapshot();
});
it('should disable confirm button by default', () => {
const { queryByText } = renderWithProvider(
<ExportPrivateKeyModal />,
mockStore,
);
const confirmButton = queryByText('Confirm');
expect(confirmButton).toBeDisabled();
});
it('should call export account with password and selected address', () => {
const { queryByTestId, queryByText } = renderWithProvider(
<ExportPrivateKeyModal />,
mockStore,
);
const passwordInput = queryByTestId('password-input');
const passwordInputEvent = {
target: {
value: password,
},
};
fireEvent.change(passwordInput, passwordInputEvent);
const confirmButton = queryByText('Confirm');
fireEvent.click(confirmButton);
expect(actions.exportAccount).toHaveBeenCalledWith(
password,
mockState.metamask.selectedAddress,
);
});
});

View File

@ -0,0 +1,93 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Hide Token Confirmation Modal should match snapshot 1`] = `
<div>
<div
class="hide-token-confirmation"
>
<div
class="hide-token-confirmation__container"
>
<div
class="hide-token-confirmation__title"
>
Hide token?
</div>
<div
class=""
>
<div
class="identicon hide-token-confirmation__identicon"
style="height: 45px; width: 45px; border-radius: 22.5px;"
>
<div
style="border-radius: 50px; overflow: hidden; padding: 0px; margin: 0px; width: 45px; height: 45px; display: inline-block; background: rgb(24, 151, 242);"
>
<svg
height="45"
width="45"
x="0"
y="0"
>
<rect
fill="#2362E1"
height="45"
transform="translate(5.047495572364477 -7.501374313922141) rotate(458.4 22.5 22.5)"
width="45"
x="0"
y="0"
/>
<rect
fill="#F94301"
height="45"
transform="translate(-21.604864626070608 11.239244487403075) rotate(268.8 22.5 22.5)"
width="45"
x="0"
y="0"
/>
<rect
fill="#FA7900"
height="45"
transform="translate(-12.763482299017626 41.456272332211) rotate(117.3 22.5 22.5)"
width="45"
x="0"
y="0"
/>
</svg>
</div>
</div>
</div>
<div
class="hide-token-confirmation__symbol"
>
TKN
</div>
<div
class="hide-token-confirmation__copy"
>
You can add this token back in the future by going to “Import token” in your accounts options menu.
</div>
<div
class="hide-token-confirmation__buttons"
>
<button
class="button btn--rounded btn-secondary hide-token-confirmation__button"
data-testid="hide-token-confirmation__cancel"
role="button"
tabindex="0"
>
Cancel
</button>
<button
class="button btn--rounded btn-primary hide-token-confirmation__button"
data-testid="hide-token-confirmation__hide"
role="button"
tabindex="0"
>
Hide
</button>
</div>
</div>
</div>
</div>
`;

View File

@ -0,0 +1,84 @@
import React from 'react';
import configureMockStore from 'redux-mock-store';
import { fireEvent } from '@testing-library/react';
import thunk from 'redux-thunk';
import * as actions from '../../../../store/actions';
import { renderWithProvider } from '../../../../../test/lib/render-helpers';
import mockState from '../../../../../test/data/mock-state.json';
import HideTokenConfirmationModal from '.';
const mockHistoryPush = jest.fn();
const mockHideModal = jest.fn();
const mockHideToken = jest.fn().mockResolvedValue();
jest.mock('../../../../store/actions.ts', () => ({
...jest.requireActual('../../../../store/actions.ts'),
hideModal: () => mockHideModal,
hideToken: () => mockHideToken,
ignoreTokens: jest.fn().mockReturnValue(jest.fn().mockResolvedValue()),
}));
describe('Hide Token Confirmation Modal', () => {
const tokenState = {
address: '0xTokenAddress',
symbol: 'TKN',
image: '',
};
const tokenModalState = {
...mockState,
appState: {
...mockState.appState,
modal: {
modalState: {
props: {
history: {
push: mockHistoryPush,
},
token: tokenState,
},
},
},
},
};
const mockStore = configureMockStore([thunk])(tokenModalState);
it('should match snapshot', () => {
const { container } = renderWithProvider(
<HideTokenConfirmationModal />,
mockStore,
);
expect(container).toMatchSnapshot();
});
it('should hide modal', () => {
const { queryByTestId } = renderWithProvider(
<HideTokenConfirmationModal />,
mockStore,
);
const cancelButton = queryByTestId('hide-token-confirmation__cancel');
fireEvent.click(cancelButton);
expect(mockHideModal).toHaveBeenCalled();
});
it('should hide token with token address from state', () => {
const { queryByTestId } = renderWithProvider(
<HideTokenConfirmationModal />,
mockStore,
);
const hideButton = queryByTestId('hide-token-confirmation__hide');
fireEvent.click(hideButton);
expect(mockHideModal).toHaveBeenCalled();
expect(actions.ignoreTokens).toHaveBeenCalledWith({
tokensToIgnore: tokenState.address,
});
});
});