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

Final conversion of tests from enzyme to @testing-library/react (#16862)

* Add transaction activity log component

* Remove duplicate tx activity log snapshot.

* Convert Advanced Tab to tlr.

* Lint fix

* Change ENS to DNS in mock state data.

* Add test ids for speedup, cancel, rety buttons.

* Convert TransactionListItemDetails component to RTL.

* Convert PageContainerHeader component to RTL.

* Convert TokenInput component to RTL.

* Convert UnitInput component to RTL.

* Convert withModalProps to RTL.

* Convert i18n-helper to RTL.

* Convert ConfirmSeedPhrase component to TLR.

* Convert AddRecipient component to RTL.

* Set process.env metamask build type to 'main' for test

Co-authored-by: Brad Decker <bhdecker84@gmail.com>
Co-authored-by: Pedro Figueiredo <pedro.figueiredo@consensys.net>
This commit is contained in:
Thomas Huang 2023-01-17 07:51:35 -08:00 committed by GitHub
parent a0bb4a6c5a
commit 4c3c4eebac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 1163 additions and 1164 deletions

View File

@ -1,5 +1,5 @@
{
"ENS": {
"DNS": {
"resolution": ""
},
"appState": {

View File

@ -1,6 +1,6 @@
{
"ENS": {
"resolution": ""
"DNS": {
"resolution": null
},
"appState": {
"networkDropdownOpen": false,

View File

@ -7,6 +7,7 @@ import log from 'loglevel';
import { JSDOM } from 'jsdom';
process.env.IN_TEST = true;
process.env.METAMASK_BUILD_TYPE = 'main';
global.chrome = {
runtime: { id: 'testid', getManifest: () => ({ manifest_version: 2 }) },

View File

@ -40,6 +40,7 @@ export default function CancelButton({
detailsModal,
})}
disabled={!hasEnoughCancelGas}
data-testid="cancel-button"
>
{t('cancel')}
</Button>

View File

@ -169,6 +169,7 @@ export default class TransactionListItemDetails extends PureComponent {
type="primary"
onClick={this.handleRetry}
className="transaction-list-item-details__header-button-rounded-button"
data-testid="speedup-button"
>
{t('speedUp')}
</Button>
@ -186,6 +187,7 @@ export default class TransactionListItemDetails extends PureComponent {
type="raised"
onClick={this.handleRetry}
className="transaction-list-item-details__header-button"
data-testid="rety-button"
>
<i className="fa fa-sync"></i>
</Button>

View File

@ -1,70 +1,19 @@
import React from 'react';
import { shallow } from 'enzyme';
import Button from '../../ui/button';
import SenderToRecipient from '../../ui/sender-to-recipient';
import TransactionBreakdown from '../transaction-breakdown';
import TransactionActivityLog from '../transaction-activity-log';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { TRANSACTION_STATUSES } from '../../../../shared/constants/transaction';
import { GAS_LIMITS } from '../../../../shared/constants/gas';
import TransactionStatus from '../transaction-status/transaction-status.component';
import TransactionListItemDetails from './transaction-list-item-details.component';
import { renderWithProvider } from '../../../../test/lib/render-helpers';
import mockState from '../../../../test/data/mock-state.json';
import TransactionListItemDetails from '.';
jest.mock('../../../store/actions.js', () => ({
tryReverseResolveAddress: () => jest.fn(),
getGasFeeEstimatesAndStartPolling: jest.fn().mockResolvedValue(),
addPollingTokenToAppState: jest.fn(),
}));
describe('TransactionListItemDetails Component', () => {
it('should render properly', () => {
const transaction = {
history: [],
id: 1,
status: TRANSACTION_STATUSES.CONFIRMED,
txParams: {
from: '0x1',
gas: GAS_LIMITS.SIMPLE,
gasPrice: '0x3b9aca00',
nonce: '0xa4',
to: '0x2',
value: '0x2386f26fc10000',
},
};
const transactionGroup = {
transactions: [transaction],
primaryTransaction: transaction,
initialTransaction: transaction,
};
const rpcPrefs = {
blockExplorerUrl: 'https://customblockexplorer.com/',
};
const blockExplorerLinkText = {
firstPart: 'addBlockExplorer',
secondPart: '',
};
const wrapper = shallow(
<TransactionListItemDetails
onClose={() => undefined}
title="Test Transaction Details"
recipientAddress="0x1"
senderAddress="0x2"
tryReverseResolveAddress={() => undefined}
transactionGroup={transactionGroup}
senderNickname="sender-nickname"
recipientNickname="recipient-nickname"
transactionStatus={TransactionStatus}
rpcPrefs={rpcPrefs}
blockExplorerLinkText={blockExplorerLinkText}
/>,
{ context: { t: (str1, str2) => (str2 ? str1 + str2 : str1) } },
);
const child = wrapper.childAt(0);
expect(child.hasClass('transaction-list-item-details')).toStrictEqual(true);
expect(child.find(Button)).toHaveLength(2);
expect(child.find(SenderToRecipient)).toHaveLength(1);
expect(child.find(TransactionBreakdown)).toHaveLength(1);
expect(child.find(TransactionActivityLog)).toHaveLength(1);
});
it('should render a retry button', () => {
const transaction = {
history: [],
id: 1,
@ -97,138 +46,80 @@ describe('TransactionListItemDetails Component', () => {
secondPart: '',
};
const wrapper = shallow(
<TransactionListItemDetails
onClose={() => undefined}
title="Test Transaction Details"
recipientAddress="0x1"
senderAddress="0x2"
tryReverseResolveAddress={() => undefined}
transactionGroup={transactionGroup}
showSpeedUp
senderNickname="sender-nickname"
recipientNickname="recipient-nickname"
transactionStatus={TransactionStatus}
rpcPrefs={rpcPrefs}
blockExplorerLinkText={blockExplorerLinkText}
/>,
{ context: { t: (str1, str2) => (str2 ? str1 + str2 : str1) } },
const props = {
onClose: jest.fn(),
title: 'Test Transaction Details',
recipientAddress: '0xAddress',
senderAddress: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
tryReverseResolveAddress: jest.fn(),
transactionGroup,
transactionStatus: () => <div></div>,
blockExplorerLinkText,
rpcPrefs,
};
it('should render title with title prop', () => {
const mockStore = configureMockStore([thunk])(mockState);
const { queryByText } = renderWithProvider(
<TransactionListItemDetails {...props} />,
mockStore,
);
const child = wrapper.childAt(0);
expect(child.hasClass('transaction-list-item-details')).toStrictEqual(true);
expect(child.find(Button)).toHaveLength(3);
expect(queryByText(props.title)).toBeInTheDocument();
});
it('should disable the Copy Tx ID and View In Etherscan buttons when tx hash is missing', () => {
const transaction = {
history: [],
id: 1,
status: 'confirmed',
txParams: {
from: '0x1',
gas: GAS_LIMITS.SIMPLE,
gasPrice: '0x3b9aca00',
nonce: '0xa4',
to: '0x2',
value: '0x2386f26fc10000',
},
describe('Retry button', () => {
it('should render retry button with showRetry prop', () => {
const retryProps = {
...props,
showRetry: true,
};
const transactionGroup = {
transactions: [transaction],
primaryTransaction: transaction,
initialTransaction: transaction,
};
const mockStore = configureMockStore([thunk])(mockState);
const rpcPrefs = {
blockExplorerUrl: 'https://customblockexplorer.com/',
};
const blockExplorerLinkText = {
firstPart: 'addBlockExplorer',
secondPart: '',
};
const wrapper = shallow(
<TransactionListItemDetails
onClose={() => undefined}
title="Test Transaction Details"
recipientAddress="0x1"
senderAddress="0x2"
tryReverseResolveAddress={() => undefined}
transactionGroup={transactionGroup}
senderNickname="sender-nickname"
recipientNickname="recipient-nickname"
transactionStatus={TransactionStatus}
rpcPrefs={rpcPrefs}
blockExplorerLinkText={blockExplorerLinkText}
/>,
{ context: { t: (str1, str2) => (str2 ? str1 + str2 : str1) } },
const { queryByTestId } = renderWithProvider(
<TransactionListItemDetails {...retryProps} />,
mockStore,
);
const child = wrapper.childAt(0);
expect(child.hasClass('transaction-list-item-details')).toStrictEqual(true);
const buttons = child.find(Button);
expect(buttons.at(0).prop('disabled')).toStrictEqual(true);
expect(buttons.at(1).prop('disabled')).toStrictEqual(true);
expect(queryByTestId('rety-button')).toBeInTheDocument();
});
});
it('should render functional Copy Tx ID and View In Etherscan buttons when tx hash exists', () => {
const transaction = {
history: [],
id: 1,
status: 'confirmed',
hash: '0xaa',
txParams: {
from: '0x1',
gas: GAS_LIMITS.SIMPLE,
gasPrice: '0x3b9aca00',
nonce: '0xa4',
to: '0x2',
value: '0x2386f26fc10000',
},
describe('Cancel button', () => {
it('should render cancel button with showCancel prop', () => {
const retryProps = {
...props,
showCancel: true,
};
const transactionGroup = {
transactions: [transaction],
primaryTransaction: transaction,
initialTransaction: transaction,
};
const mockStore = configureMockStore([thunk])(mockState);
const rpcPrefs = {
blockExplorerUrl: 'https://customblockexplorer.com/',
};
const blockExplorerLinkText = {
firstPart: 'addBlockExplorer',
secondPart: '',
};
const wrapper = shallow(
<TransactionListItemDetails
onClose={() => undefined}
title="Test Transaction Details"
recipientAddress="0x1"
senderAddress="0x2"
tryReverseResolveAddress={() => undefined}
transactionGroup={transactionGroup}
senderNickname="sender-nickname"
recipientNickname="recipient-nickname"
transactionStatus={TransactionStatus}
rpcPrefs={rpcPrefs}
blockExplorerLinkText={blockExplorerLinkText}
/>,
{ context: { t: (str1, str2) => (str2 ? str1 + str2 : str1) } },
const { queryByTestId } = renderWithProvider(
<TransactionListItemDetails {...retryProps} />,
mockStore,
);
const child = wrapper.childAt(0);
expect(queryByTestId('cancel-button')).toBeInTheDocument();
});
});
expect(child.hasClass('transaction-list-item-details')).toStrictEqual(true);
const buttons = child.find(Button);
expect(buttons.at(0).prop('disabled')).toStrictEqual(false);
expect(buttons.at(1).prop('disabled')).toStrictEqual(false);
describe('Speedup button', () => {
it('should render speedup button with showSpeedUp prop', () => {
const retryProps = {
...props,
showSpeedUp: true,
};
const mockStore = configureMockStore([thunk])(mockState);
const { queryByTestId } = renderWithProvider(
<TransactionListItemDetails {...retryProps} />,
mockStore,
);
expect(queryByTestId('speedup-button')).toBeInTheDocument();
});
});
});

View File

@ -0,0 +1,39 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Page Container Header should match snapshot 1`] = `
<div>
<div
class="page-container__header page-container__header--no-padding-bottom"
data-testid="page-container__header"
>
<div
class="page-container__header-row"
>
<span
class="page-container__back-button"
>
Back
</span>
</div>
<div
class="page-container__title"
>
Test Title
</div>
<div
class="page-container__subtitle"
>
Test Subtitle
</div>
<button
aria-label="close"
class="page-container__header-close"
/>
<ul
class="page-container__tabs"
>
Test Tab
</ul>
</div>
</div>
`;

View File

@ -1,85 +0,0 @@
import React from 'react';
import { shallow } from 'enzyme';
import sinon from 'sinon';
import PageContainerHeader from './page-container-header.component';
describe('Page Container Header', () => {
let wrapper, style, onBackButtonClick, onClose;
beforeEach(() => {
style = { test: 'style' };
onBackButtonClick = sinon.spy();
onClose = sinon.spy();
wrapper = shallow(
<PageContainerHeader
showBackButton
onBackButtonClick={onBackButtonClick}
backButtonStyles={style}
title="Test Title"
subtitle="Test Subtitle"
tabs="Test Tab"
onClose={onClose}
/>,
);
});
describe('Render Header Row', () => {
it('renders back button', () => {
expect(wrapper.find('.page-container__back-button')).toHaveLength(1);
expect(wrapper.find('.page-container__back-button').text()).toStrictEqual(
'Back',
);
});
it('ensures style prop', () => {
expect(
wrapper.find('.page-container__back-button').props().style,
).toStrictEqual(style);
});
it('should call back button when click is simulated', () => {
wrapper.find('.page-container__back-button').prop('onClick')();
expect(onBackButtonClick.callCount).toStrictEqual(1);
});
});
describe('Render', () => {
let header, headerRow, pageTitle, pageSubtitle, pageClose, pageTab;
beforeEach(() => {
header = wrapper.find('.page-container__header--no-padding-bottom');
headerRow = wrapper.find('.page-container__header-row');
pageTitle = wrapper.find('.page-container__title');
pageSubtitle = wrapper.find('.page-container__subtitle');
pageClose = wrapper.find('.page-container__header-close');
pageTab = wrapper.find('.page-container__tabs');
});
it('renders page container', () => {
expect(header).toHaveLength(1);
expect(headerRow).toHaveLength(1);
expect(pageTitle).toHaveLength(1);
expect(pageSubtitle).toHaveLength(1);
expect(pageClose).toHaveLength(1);
expect(pageTab).toHaveLength(1);
});
it('renders title', () => {
expect(pageTitle.text()).toStrictEqual('Test Title');
});
it('renders subtitle', () => {
expect(pageSubtitle.text()).toStrictEqual('Test Subtitle');
});
it('renders tabs', () => {
expect(pageTab.text()).toStrictEqual('Test Tab');
});
it('should call close when click is simulated', () => {
pageClose.prop('onClick')();
expect(onClose.callCount).toStrictEqual(1);
});
});
});

View File

@ -0,0 +1,36 @@
import React from 'react';
import { fireEvent } from '@testing-library/react';
import { renderWithProvider } from '../../../../../test/lib/render-helpers';
import PageContainerHeader from '.';
describe('Page Container Header', () => {
const props = {
showBackButton: true,
onBackButtonClick: jest.fn(),
backButtonStyles: { test: 'style' },
title: 'Test Title',
subtitle: 'Test Subtitle',
tabs: 'Test Tab',
onClose: jest.fn(),
};
it('should match snapshot', () => {
const { container } = renderWithProvider(
<PageContainerHeader {...props} />,
);
expect(container).toMatchSnapshot();
});
it('should call back button when click is simulated', () => {
const { queryByText } = renderWithProvider(
<PageContainerHeader {...props} />,
);
const backButton = queryByText('Back');
fireEvent.click(backButton);
expect(props.onBackButtonClick).toHaveBeenCalled();
});
});

View File

@ -0,0 +1,37 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TokenInput Component Name of the group should render properly 1`] = `
<div>
<div
class="unit-input"
>
<div
class="unit-input__inputs"
>
<div
class="unit-input__input-container"
>
<input
class="unit-input__input"
data-testid="token-input"
dir="ltr"
placeholder="0"
style="width: 1.5ch;"
type="number"
value="0"
/>
<div
class="unit-input__suffix"
>
TEST
</div>
</div>
<div
class="currency-input__conversion-component"
>
No conversion rate available
</div>
</div>
</div>
</div>
`;

View File

@ -24,6 +24,7 @@ export default class TokenInput extends PureComponent {
};
static propTypes = {
dataTestId: PropTypes.string,
currentCurrency: PropTypes.string,
onChange: PropTypes.func,
value: PropTypes.string,

View File

@ -1,513 +1,117 @@
import React from 'react';
import PropTypes from 'prop-types';
import { shallow, mount } from 'enzyme';
import { Provider } from 'react-redux';
import configureMockStore from 'redux-mock-store';
import UnitInput from '../unit-input';
import CurrencyDisplay from '../currency-display';
import TokenInput from './token-input.component';
import { fireEvent } from '@testing-library/react';
import { renderWithProvider } from '../../../../test/lib/render-helpers';
import mockState from '../../../../test/data/mock-state.json';
import TokenInput from '.';
describe('TokenInput Component', () => {
const t = (key) => `translate ${key}`;
const props = {
dataTestId: 'token-input',
onChange: jest.fn(),
token: {
address: '0x108cf70c7d384c552f42c07c41c0e1e46d77ea0d',
symbol: 'TEST',
decimals: 0,
},
};
describe('rendering', () => {
afterEach(() => {
props.onChange.mockReset();
});
describe('Name of the group', () => {
it('should render properly', () => {
const mockStore = {
const mockStore = configureMockStore()(mockState);
const { container } = renderWithProvider(
<TokenInput {...props} />,
mockStore,
);
expect(container).toMatchSnapshot();
});
});
describe('Conversion Display', () => {
it('should render conversionRate', () => {
const showFiatState = {
...mockState,
metamask: {
currentCurrency: 'usd',
conversionRate: 231.06,
...mockState.metamask,
preferences: {
...mockState.metamask.preferences,
showFiatInTestnets: true,
},
},
};
const store = configureMockStore()(mockStore);
const mockStore = configureMockStore()(showFiatState);
const wrapper = mount(
<Provider store={store}>
<TokenInput
token={{
address: '0x1',
decimals: 4,
symbol: 'ABC',
}}
tokens={[
{
address: '0x1',
decimals: 4,
symbol: 'ABC',
image: null,
isERC721: false,
},
]}
/>
</Provider>,
{
context: { t },
childContextTypes: {
t: PropTypes.func,
},
},
const { queryByTitle } = renderWithProvider(
<TokenInput {...props} />,
mockStore,
);
expect(wrapper).toHaveLength(1);
expect(wrapper.find('.unit-input__suffix')).toHaveLength(1);
expect(wrapper.find('.unit-input__suffix').text()).toStrictEqual('ABC');
expect(
wrapper.find('.currency-input__conversion-component'),
).toHaveLength(1);
expect(
wrapper.find('.currency-input__conversion-component').text(),
).toStrictEqual('translate noConversionRateAvailable');
expect(queryByTitle('0 ETH')).toBeInTheDocument();
});
it('should render properly with tokenExchangeRates', () => {
const mockStore = {
it('should render showFiat', () => {
const showFiatState = {
...mockState,
metamask: {
currentCurrency: 'usd',
conversionRate: 231.06,
...mockState.metamask,
preferences: {
...mockState.metamask.preferences,
showFiatInTestnets: true,
},
},
};
const store = configureMockStore()(mockStore);
const wrapper = mount(
<Provider store={store}>
<TokenInput
token={{
address: '0x1',
decimals: 4,
symbol: 'ABC',
}}
tokens={[
{
address: '0x1',
decimals: 4,
symbol: 'ABC',
image: null,
isERC721: false,
},
]}
tokenExchangeRates={{ '0x1': 2 }}
/>
</Provider>,
{
context: { t },
childContextTypes: {
t: PropTypes.func,
},
},
);
expect(wrapper).toHaveLength(1);
expect(wrapper.find('.unit-input__suffix')).toHaveLength(1);
expect(wrapper.find('.unit-input__suffix').text()).toStrictEqual('ABC');
expect(wrapper.find(CurrencyDisplay)).toHaveLength(1);
});
it('should render properly with a token value for ETH', () => {
const mockStore = {
metamask: {
currentCurrency: 'usd',
conversionRate: 231.06,
},
const showFiatProps = {
...props,
showFiat: true,
};
const store = configureMockStore()(mockStore);
const wrapper = mount(
<Provider store={store}>
<TokenInput
value="2710"
token={{
address: '0x1',
decimals: 4,
symbol: 'ABC',
}}
tokens={[
{
address: '0x1',
decimals: 4,
symbol: 'ABC',
image: null,
isERC721: false,
},
]}
tokenExchangeRates={{ '0x1': 2 }}
/>
</Provider>,
const mockStore = configureMockStore()(showFiatState);
const { queryByTitle } = renderWithProvider(
<TokenInput {...showFiatProps} />,
mockStore,
);
expect(wrapper).toHaveLength(1);
const tokenInputInstance = wrapper.find(TokenInput).at(0).instance();
expect(tokenInputInstance.state.decimalValue).toStrictEqual('1');
expect(tokenInputInstance.state.hexValue).toStrictEqual('2710');
expect(wrapper.find('.unit-input__suffix')).toHaveLength(1);
expect(wrapper.find('.unit-input__suffix').text()).toStrictEqual('ABC');
expect(wrapper.find('.unit-input__input').props().value).toStrictEqual(
'1',
);
expect(wrapper.find('.currency-display-component').text()).toStrictEqual(
'2ETH',
);
});
it('should render properly with a token value for fiat', () => {
const mockStore = {
metamask: {
currentCurrency: 'usd',
conversionRate: 231.06,
},
};
const store = configureMockStore()(mockStore);
const wrapper = mount(
<Provider store={store}>
<TokenInput
value="2710"
token={{
address: '0x1',
decimals: 4,
symbol: 'ABC',
}}
tokens={[
{
address: '0x1',
decimals: 4,
symbol: 'ABC',
image: null,
isERC721: false,
},
]}
tokenExchangeRates={{ '0x1': 2 }}
showFiat
currentCurrency="usd"
/>
</Provider>,
);
expect(wrapper).toHaveLength(1);
const tokenInputInstance = wrapper.find(TokenInput).at(0).instance();
expect(tokenInputInstance.state.decimalValue).toStrictEqual('1');
expect(tokenInputInstance.state.hexValue).toStrictEqual('2710');
expect(wrapper.find('.unit-input__suffix')).toHaveLength(1);
expect(wrapper.find('.unit-input__suffix').text()).toStrictEqual('ABC');
expect(wrapper.find('.unit-input__input').props().value).toStrictEqual(
'1',
);
expect(wrapper.find('.currency-display-component').text()).toStrictEqual(
'$462.12USD',
);
});
it('should render properly with a token value for fiat, but hideConversion is true', () => {
const mockStore = {
metamask: {
currentCurrency: 'usd',
conversionRate: 231.06,
},
};
const store = configureMockStore()(mockStore);
const wrapper = mount(
<Provider store={store}>
<TokenInput
value="2710"
token={{
address: '0x1',
decimals: 4,
symbol: 'ABC',
}}
tokens={[
{
address: '0x1',
decimals: 4,
symbol: 'ABC',
image: null,
isERC721: false,
},
]}
tokenExchangeRates={{ '0x1': 2 }}
showFiat
hideConversion
/>
</Provider>,
{
context: { t },
childContextTypes: {
t: PropTypes.func,
},
},
);
expect(wrapper).toHaveLength(1);
const tokenInputInstance = wrapper.find(TokenInput).at(0).instance();
expect(tokenInputInstance.state.decimalValue).toStrictEqual('1');
expect(tokenInputInstance.state.hexValue).toStrictEqual('2710');
expect(wrapper.find('.unit-input__suffix')).toHaveLength(1);
expect(wrapper.find('.unit-input__suffix').text()).toStrictEqual('ABC');
expect(wrapper.find('.unit-input__input').props().value).toStrictEqual(
'1',
);
expect(
wrapper.find('.currency-input__conversion-component').text(),
).toStrictEqual('translate noConversionRateAvailable');
expect(queryByTitle('$0.00 USD')).toBeInTheDocument();
});
});
describe('handling actions', () => {
const handleChangeSpy = jest.fn();
describe('handle', () => {
it('should handle', () => {
const mockStore = configureMockStore()(mockState);
afterEach(() => {
handleChangeSpy.mockClear();
const { queryByTestId } = renderWithProvider(
<TokenInput {...props} />,
mockStore,
);
const tokenInput = queryByTestId('token-input');
fireEvent.change(tokenInput, { target: { value: '2' } });
expect(props.onChange).toHaveBeenCalledWith('2');
});
it('should call onChange on input changes with the hex value for ETH', () => {
const mockStore = {
metamask: {
currentCurrency: 'usd',
conversionRate: 231.06,
},
};
const store = configureMockStore()(mockStore);
const wrapper = mount(
<Provider store={store}>
<TokenInput
onChange={handleChangeSpy}
token={{
address: '0x1',
decimals: 4,
symbol: 'ABC',
}}
tokens={[
{
address: '0x1',
decimals: 4,
symbol: 'ABC',
image: null,
isERC721: false,
},
]}
tokenExchangeRates={{ '0x1': 2 }}
/>
</Provider>,
it('should blur', () => {
const mockStore = configureMockStore()(mockState);
const { queryByTestId } = renderWithProvider(
<TokenInput {...props} />,
mockStore,
);
expect(wrapper).toHaveLength(1);
expect(handleChangeSpy.mock.calls).toHaveLength(0);
const tokenInput = queryByTestId('token-input');
const tokenInputInstance = wrapper.find(TokenInput).at(0).instance();
expect(tokenInputInstance.state.decimalValue).toStrictEqual(0);
expect(tokenInputInstance.state.hexValue).toBeUndefined();
expect(wrapper.find('.currency-display-component').text()).toStrictEqual(
'0ETH',
);
const input = wrapper.find('input');
expect(input.props().value).toStrictEqual(0);
fireEvent.blur(tokenInput, { target: { value: '2' } });
input.simulate('change', { target: { value: '1' } });
expect(handleChangeSpy.mock.calls).toHaveLength(1);
expect(handleChangeSpy.mock.calls[0][0]).toStrictEqual('2710');
expect(wrapper.find('.currency-display-component').text()).toStrictEqual(
'2ETH',
);
expect(tokenInputInstance.state.decimalValue).toStrictEqual('1');
expect(tokenInputInstance.state.hexValue).toStrictEqual('2710');
});
it('should call onChange on input changes with the hex value for fiat', () => {
const mockStore = {
metamask: {
currentCurrency: 'usd',
conversionRate: 231.06,
},
};
const store = configureMockStore()(mockStore);
const wrapper = mount(
<Provider store={store}>
<TokenInput
onChange={handleChangeSpy}
token={{
address: '0x1',
decimals: 4,
symbol: 'ABC',
}}
tokens={[
{
address: '0x1',
decimals: 4,
symbol: 'ABC',
image: null,
isERC721: false,
},
]}
tokenExchangeRates={{ '0x1': 2 }}
showFiat
currentCurrency="usd"
/>
</Provider>,
);
expect(wrapper).toHaveLength(1);
expect(handleChangeSpy.mock.calls).toHaveLength(0);
const tokenInputInstance = wrapper.find(TokenInput).at(0).instance();
expect(tokenInputInstance.state.decimalValue).toStrictEqual(0);
expect(tokenInputInstance.state.hexValue).toBeUndefined();
expect(wrapper.find('.currency-display-component').text()).toStrictEqual(
'$0.00USD',
);
const input = wrapper.find('input');
expect(input.props().value).toStrictEqual(0);
input.simulate('change', { target: { value: '1' } });
expect(handleChangeSpy.mock.calls).toHaveLength(1);
expect(handleChangeSpy.mock.calls[0][0]).toStrictEqual('2710');
expect(wrapper.find('.currency-display-component').text()).toStrictEqual(
'$462.12USD',
);
expect(tokenInputInstance.state.decimalValue).toStrictEqual('1');
expect(tokenInputInstance.state.hexValue).toStrictEqual('2710');
});
it('should change the state and pass in a new decimalValue when props.value changes', () => {
const mockStore = {
metamask: {
currentCurrency: 'usd',
conversionRate: 231.06,
},
};
const store = configureMockStore()(mockStore);
const wrapper = shallow(
<Provider store={store}>
<TokenInput
onChange={handleChangeSpy}
token={{
address: '0x1',
decimals: 4,
symbol: 'ABC',
}}
tokens={[
{
address: '0x1',
decimals: 4,
symbol: 'ABC',
image: null,
isERC721: false,
},
]}
tokenExchangeRates={{ '0x1': 2 }}
showFiat
/>
</Provider>,
);
expect(wrapper).toHaveLength(1);
const tokenInputInstance = wrapper.find(TokenInput).dive();
expect(tokenInputInstance.state('decimalValue')).toStrictEqual(0);
expect(tokenInputInstance.state('hexValue')).toBeUndefined();
expect(tokenInputInstance.find(UnitInput).props().value).toStrictEqual(0);
tokenInputInstance.setProps({ value: '2710' });
tokenInputInstance.update();
expect(tokenInputInstance.state('decimalValue')).toStrictEqual('1');
expect(tokenInputInstance.state('hexValue')).toStrictEqual('2710');
expect(tokenInputInstance.find(UnitInput).props().value).toStrictEqual(
'1',
);
});
});
describe('Token Input Decimals Check', () => {
const handleChangeSpy = jest.fn();
afterEach(() => {
handleChangeSpy.mockClear();
});
it('should render incorrect hex onChange when input decimals is more than token decimals', () => {
const mockStore = {
metamask: {
currentCurrency: 'usd',
conversionRate: 231.06,
},
};
const store = configureMockStore()(mockStore);
const wrapper = mount(
<Provider store={store}>
<TokenInput
onChange={handleChangeSpy}
token={{
address: '0x1',
decimals: 4,
symbol: 'ABC',
}}
tokens={[
{
address: '0x1',
decimals: 4,
symbol: 'ABC',
image: null,
isERC721: false,
},
]}
tokenExchangeRates={{ '0x1': 2 }}
showFiat
currentCurrency="usd"
/>
</Provider>,
);
expect(wrapper).toHaveLength(1);
expect(handleChangeSpy.mock.calls).toHaveLength(0);
const input = wrapper.find('input');
expect(input.props().value).toStrictEqual(0);
input.simulate('change', { target: { value: '1.11111' } });
expect(handleChangeSpy.mock.calls).toHaveLength(1);
expect(handleChangeSpy.mock.calls[0][0]).toStrictEqual(
'2b67.1999999999999999999a',
);
});
it('should render correct hex onChange when input decimals is more than token decimals by omitting excess fractional part on blur', () => {
const mockStore = {
metamask: {
currentCurrency: 'usd',
conversionRate: 231.06,
},
};
const store = configureMockStore()(mockStore);
const wrapper = mount(
<Provider store={store}>
<TokenInput
onChange={handleChangeSpy}
token={{
address: '0x1',
decimals: 4,
symbol: 'ABC',
}}
tokens={[
{
address: '0x1',
decimals: 4,
symbol: 'ABC',
image: null,
isERC721: false,
},
]}
tokenExchangeRates={{ '0x1': 2 }}
showFiat
currentCurrency="usd"
/>
</Provider>,
);
expect(wrapper).toHaveLength(1);
const input = wrapper.find('input');
input.simulate('blur', { target: { value: '1.11111' } });
expect(handleChangeSpy.mock.calls).toHaveLength(1);
expect(handleChangeSpy.mock.calls[0][0]).toStrictEqual('2b67');
expect(props.onChange).toHaveBeenCalledWith('2');
});
});
});

View File

@ -0,0 +1,111 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`UnitInput Component rendering should match snapshot of error class when props.error === true 1`] = `
<div>
<div
class="unit-input unit-input--error"
>
<div
class="unit-input__inputs"
>
<div
class="unit-input__input-container"
>
<input
class="unit-input__input"
dir="ltr"
placeholder="0"
style="width: 1.5ch;"
type="number"
value=""
/>
</div>
</div>
</div>
</div>
`;
exports[`UnitInput Component rendering should match snapshot with a child component 1`] = `
<div>
<div
class="unit-input"
>
<div
class="unit-input__inputs"
>
<div
class="unit-input__input-container"
>
<input
class="unit-input__input"
dir="ltr"
placeholder="0"
style="width: 1.5ch;"
type="number"
value=""
/>
</div>
<div
class="testing"
>
TESTCOMPONENT
</div>
</div>
</div>
</div>
`;
exports[`UnitInput Component rendering should match snapshot with a suffix 1`] = `
<div>
<div
class="unit-input"
>
<div
class="unit-input__inputs"
>
<div
class="unit-input__input-container"
>
<input
class="unit-input__input"
dir="ltr"
placeholder="0"
style="width: 1.5ch;"
type="number"
value=""
/>
<div
class="unit-input__suffix"
>
ETH
</div>
</div>
</div>
</div>
</div>
`;
exports[`UnitInput Component rendering should match snapshot without a suffix 1`] = `
<div>
<div
class="unit-input"
>
<div
class="unit-input__inputs"
>
<div
class="unit-input__input-container"
>
<input
class="unit-input__input"
dir="ltr"
placeholder="0"
style="width: 1.5ch;"
type="number"
value=""
/>
</div>
</div>
</div>
</div>
`;

View File

@ -1,98 +1,59 @@
import React from 'react';
import { shallow, mount } from 'enzyme';
import sinon from 'sinon';
import { fireEvent } from '@testing-library/react';
import { renderWithProvider } from '../../../../test/lib/render-helpers';
import UnitInput from './unit-input.component';
describe('UnitInput Component', () => {
describe('rendering', () => {
it('should render properly without a suffix', () => {
const wrapper = shallow(<UnitInput />);
it('should match snapshot without a suffix', () => {
const { container } = renderWithProvider(<UnitInput />);
expect(wrapper).toHaveLength(1);
expect(wrapper.find('.unit-input__suffix')).toHaveLength(0);
expect(container).toMatchSnapshot();
});
it('should render properly with a suffix', () => {
const wrapper = shallow(<UnitInput suffix="ETH" />);
it('should match snapshot with a suffix', () => {
const { container } = renderWithProvider(<UnitInput suffix="ETH" />);
expect(wrapper).toHaveLength(1);
expect(wrapper.find('.unit-input__suffix')).toHaveLength(1);
expect(wrapper.find('.unit-input__suffix').text()).toStrictEqual('ETH');
expect(container).toMatchSnapshot();
});
it('should render properly with a child component', () => {
const wrapper = shallow(
it('should match snapshot with a child component', () => {
const { container } = renderWithProvider(
<UnitInput>
<div className="testing">TESTCOMPONENT</div>
</UnitInput>,
);
expect(wrapper).toHaveLength(1);
expect(wrapper.find('.testing')).toHaveLength(1);
expect(wrapper.find('.testing').text()).toStrictEqual('TESTCOMPONENT');
expect(container).toMatchSnapshot();
});
it('should render with an error class when props.error === true', () => {
const wrapper = shallow(<UnitInput error />);
it('should match snapshot of error class when props.error === true', () => {
const { container } = renderWithProvider(<UnitInput error />);
expect(wrapper).toHaveLength(1);
expect(wrapper.find('.unit-input--error')).toHaveLength(1);
expect(container).toMatchSnapshot();
});
});
describe('handling actions', () => {
const handleChangeSpy = sinon.spy();
const handleBlurSpy = sinon.spy();
const handleChangeSpy = jest.fn();
const handleOnBlurSpy = jest.fn();
afterEach(() => {
handleChangeSpy.resetHistory();
handleBlurSpy.resetHistory();
});
it('should call onChange and onBlur on input changes with the value', async () => {
const { queryByTestId } = renderWithProvider(
<UnitInput
onChange={handleChangeSpy}
onBlur={handleOnBlurSpy}
dataTestId="unit-input"
/>,
);
it('should focus the input on component click', () => {
const wrapper = mount(<UnitInput />);
const input = queryByTestId('unit-input');
expect(wrapper).toHaveLength(1);
const handleFocusSpy = sinon.spy(wrapper.instance(), 'handleFocus');
wrapper.instance().forceUpdate();
wrapper.update();
expect(handleFocusSpy.callCount).toStrictEqual(0);
wrapper.find('.unit-input').simulate('click');
expect(handleFocusSpy.callCount).toStrictEqual(1);
});
fireEvent.blur(input);
fireEvent.change(input, { target: { value: 2 } });
it('should call onChange on input changes with the value', () => {
const wrapper = mount(<UnitInput onChange={handleChangeSpy} />);
expect(wrapper).toHaveLength(1);
expect(handleChangeSpy.callCount).toStrictEqual(0);
const input = wrapper.find('input');
input.simulate('change', { target: { value: 123 } });
expect(handleChangeSpy.callCount).toStrictEqual(1);
expect(handleChangeSpy.calledWith(123)).toStrictEqual(true);
expect(wrapper.state('value')).toStrictEqual(123);
});
it('should set the component state value with props.value', () => {
const wrapper = mount(<UnitInput value={123} />);
expect(wrapper).toHaveLength(1);
expect(wrapper.state('value')).toStrictEqual(123);
});
it('should update the component state value with props.value', () => {
const wrapper = mount(<UnitInput onChange={handleChangeSpy} />);
expect(wrapper).toHaveLength(1);
expect(handleChangeSpy.callCount).toStrictEqual(0);
const input = wrapper.find('input');
input.simulate('change', { target: { value: 123 } });
expect(wrapper.state('value')).toStrictEqual(123);
expect(handleChangeSpy.callCount).toStrictEqual(1);
expect(handleChangeSpy.calledWith(123)).toStrictEqual(true);
wrapper.setProps({ value: 456 });
expect(wrapper.state('value')).toStrictEqual(456);
expect(handleChangeSpy.callCount).toStrictEqual(1);
expect(handleOnBlurSpy).toHaveBeenCalled();
expect(handleChangeSpy).toHaveBeenCalledWith('2');
});
});
});

View File

@ -0,0 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`withModalProps should return a component wrapped with modal state props 1`] = `
<div>
<div
class="test"
>
Testing
</div>
</div>
`;

View File

@ -1,6 +1,6 @@
import configureMockStore from 'redux-mock-store';
import { mount } from 'enzyme';
import React from 'react';
import { renderWithProvider } from '../../../../test/lib/render-helpers';
import withModalProps from './with-modal-props';
const mockState = {
@ -22,16 +22,10 @@ describe('withModalProps', () => {
const TestComponent = () => <div className="test">Testing</div>;
const WrappedComponent = withModalProps(TestComponent);
const store = configureMockStore()(mockState);
const wrapper = mount(<WrappedComponent store={store} />);
const { container } = renderWithProvider(
<WrappedComponent store={store} />,
);
expect(wrapper).toHaveLength(1);
const testComponent = wrapper.find(TestComponent).at(0);
expect(testComponent).toHaveLength(1);
expect(testComponent.find('.test').text()).toStrictEqual('Testing');
const testComponentProps = testComponent.props();
expect(testComponentProps.prop1).toStrictEqual('prop1');
expect(testComponentProps.prop2).toStrictEqual(2);
expect(testComponentProps.prop3).toStrictEqual(true);
expect(typeof testComponentProps.hideModal).toStrictEqual('function');
expect(container).toMatchSnapshot();
});
});

View File

@ -0,0 +1,65 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`i18n helper getMessage should return the correct message when a single react substitution is made 1`] = `
<div>
<span>
Testing a react substitution
<div
style="color: red;"
>
TEST_SUBSTITUTION_1
</div>
.
</span>
</div>
`;
exports[`i18n helper getMessage should return the correct message when substituting a mix of react elements and strings 1`] = `
<div>
<span>
Testing a mix
TEST_SUBSTITUTION_1
of react substitutions
<div
style="color: orange;"
>
TEST_SUBSTITUTION_3
</div>
and string substitutions
TEST_SUBSTITUTION_2
+
<div
style="color: pink;"
>
TEST_SUBSTITUTION_4
</div>
.
</span>
</div>
`;
exports[`i18n helper getMessage should return the correct message when two react substitutions are made 1`] = `
<div>
<span>
Testing a react substitution
<div
style="color: red;"
>
TEST_SUBSTITUTION_1
</div>
and another
<div
style="color: blue;"
>
TEST_SUBSTITUTION_2
</div>
.
</span>
</div>
`;

View File

@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from 'enzyme';
import { renderWithProvider } from '../../../test/lib/render-helpers';
import { getMessage } from './i18n-helper';
describe('i18n helper', () => {
@ -76,17 +76,17 @@ describe('i18n helper', () => {
</div>
);
const TEST_SUBSTITUTION_7_1 = (
<div style={{ color: 'red' }} key="test-react-substitutions-1">
<div style={{ color: 'red' }} key="test-react-substitutions-7-1">
{t(TEST_KEY_7_HELPER_1)}
</div>
);
const TEST_SUBSTITUTION_7_2 = (
<div style={{ color: 'blue' }} key="test-react-substitutions-1">
<div style={{ color: 'blue' }} key="test-react-substitutions-7-2">
{t(TEST_KEY_7_HELPER_2)}
</div>
);
const TEST_SUBSTITUTION_8_1 = (
<div style={{ color: 'orange' }} key="test-react-substitutions-1">
<div style={{ color: 'orange' }} key="test-react-substitutions-8-1">
{t(TEST_KEY_8_HELPER_1)}
</div>
);
@ -141,9 +141,10 @@ describe('i18n helper', () => {
it('should return the correct message when a single react substitution is made', () => {
const result = t(TEST_KEY_6, [TEST_SUBSTITUTION_6]);
expect(shallow(result).html()).toStrictEqual(
'<span> Testing a react substitution <div style="color:red">TEST_SUBSTITUTION_1</div>. </span>',
);
const { container } = renderWithProvider(result);
expect(container).toMatchSnapshot();
});
it('should return the correct message when two react substitutions are made', () => {
@ -151,9 +152,10 @@ describe('i18n helper', () => {
TEST_SUBSTITUTION_7_1,
TEST_SUBSTITUTION_7_2,
]);
expect(shallow(result).html()).toStrictEqual(
'<span> Testing a react substitution <div style="color:red">TEST_SUBSTITUTION_1</div> and another <div style="color:blue">TEST_SUBSTITUTION_2</div>. </span>',
);
const { container } = renderWithProvider(result);
expect(container).toMatchSnapshot();
});
it('should return the correct message when substituting a mix of react elements and strings', () => {
@ -163,9 +165,10 @@ describe('i18n helper', () => {
TEST_SUBSTITUTION_2,
TEST_SUBSTITUTION_8_2,
]);
expect(shallow(result).html()).toStrictEqual(
'<span> Testing a mix TEST_SUBSTITUTION_1 of react substitutions <div style="color:orange">TEST_SUBSTITUTION_3</div> and string substitutions TEST_SUBSTITUTION_2 + <div style="color:pink">TEST_SUBSTITUTION_4</div>. </span>',
);
const { container } = renderWithProvider(result);
expect(container).toMatchSnapshot();
});
});
});

View File

@ -1,125 +1,43 @@
import React from 'react';
import { shallow } from 'enzyme';
import sinon from 'sinon';
import ConfirmSeedPhrase from './confirm-seed-phrase/confirm-seed-phrase.component';
import { DragDropContextProvider } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import configureMockStore from 'redux-mock-store';
import { fireEvent, waitFor } from '@testing-library/react';
import thunk from 'redux-thunk';
import { renderWithProvider } from '../../../../test/lib/render-helpers';
import ConfirmSeedPhrase from './confirm-seed-phrase';
function shallowRender(props = {}, context = {}) {
return shallow(<ConfirmSeedPhrase {...props} />, {
context: {
t: (str) => `${str}_t`,
...context,
},
});
jest.mock('../../../store/actions.js', () => ({
setSeedPhraseBackedUp: () => jest.fn().mockResolvedValue(),
}));
const seedPhrase = '鼠 牛 虎 兔 龍 蛇 馬 羊 猴 雞 狗 豬';
function shallowRender(props = {}) {
const mockState = {};
const mockStore = configureMockStore([thunk])(mockState);
return renderWithProvider(
<DragDropContextProvider backend={HTML5Backend}>
<ConfirmSeedPhrase {...props} />
</DragDropContextProvider>,
mockStore,
);
}
describe('ConfirmSeedPhrase Component', () => {
it('should render correctly', () => {
const component = shallowRender({
seedPhrase: '鼠 牛 虎 兔 龍 蛇 馬 羊 猴 雞 狗 豬',
const { queryAllByTestId } = shallowRender({
seedPhrase,
});
expect(
component.find('.confirm-seed-phrase__seed-word--sorted'),
).toHaveLength(12);
});
it('should add/remove selected on click', () => {
const trackEventSpy = sinon.spy();
const replaceSpy = sinon.spy();
const component = shallowRender(
{
seedPhrase: '鼠 牛 虎 兔 龍 蛇 馬 羊 猴 雞 狗 豬',
history: { replace: replaceSpy },
},
{
trackEvent: trackEventSpy,
},
// Regex ommitted the empty/undefined draggable boxes
expect(queryAllByTestId(/draggable-seed-(?!.*undefined)/u)).toHaveLength(
12,
);
const seeds = component.find('.confirm-seed-phrase__seed-word--sorted');
// Click on 3 seeds to add to selected
seeds.at(0).simulate('click');
seeds.at(1).simulate('click');
seeds.at(2).simulate('click');
expect(component.state().selectedSeedIndices).toStrictEqual([0, 1, 2]);
// Click on a selected seed to remove
component.state();
component.update();
component.state();
component
.find('.confirm-seed-phrase__seed-word--sorted')
.at(1)
.simulate('click');
expect(component.state().selectedSeedIndices).toStrictEqual([0, 2]);
});
it('should render correctly on hover', () => {
const trackEventSpy = sinon.spy();
const replaceSpy = sinon.spy();
const component = shallowRender(
{
seedPhrase: '鼠 牛 虎 兔 龍 蛇 馬 羊 猴 雞 狗 豬',
history: { replace: replaceSpy },
},
{
trackEvent: trackEventSpy,
},
);
const seeds = component.find('.confirm-seed-phrase__seed-word--sorted');
// Click on 3 seeds to add to selected
seeds.at(0).simulate('click');
seeds.at(1).simulate('click');
seeds.at(2).simulate('click');
// Dragging Seed # 2 to 0 placeth
component.instance().setDraggingSeedIndex(2);
component.instance().setHoveringIndex(0);
component.update();
const pendingSeeds = component.find(
'.confirm-seed-phrase__selected-seed-words__pending-seed',
);
expect(pendingSeeds.at(0).props().seedIndex).toStrictEqual(2);
expect(pendingSeeds.at(1).props().seedIndex).toStrictEqual(0);
expect(pendingSeeds.at(2).props().seedIndex).toStrictEqual(1);
});
it('should insert seed in place on drop', () => {
const trackEventSpy = sinon.spy();
const replaceSpy = sinon.spy();
const component = shallowRender(
{
seedPhrase: '鼠 牛 虎 兔 龍 蛇 馬 羊 猴 雞 狗 豬',
history: { replace: replaceSpy },
},
{
trackEvent: trackEventSpy,
},
);
const seeds = component.find('.confirm-seed-phrase__seed-word--sorted');
// Click on 3 seeds to add to selected
seeds.at(0).simulate('click');
seeds.at(1).simulate('click');
seeds.at(2).simulate('click');
// Drop Seed # 2 to 0 placeth
component.instance().setDraggingSeedIndex(2);
component.instance().setHoveringIndex(0);
component.instance().onDrop(0);
component.update();
expect(component.state().selectedSeedIndices).toStrictEqual([2, 0, 1]);
expect(component.state().pendingSeedIndices).toStrictEqual([2, 0, 1]);
// For 24 word mnemonic phrases.
expect(queryAllByTestId(/draggable-seed-undefined/u)).toHaveLength(24);
});
it('should submit correctly', async () => {
@ -137,41 +55,25 @@ describe('ConfirmSeedPhrase Component', () => {
'狗',
'豬',
];
const trackEventSpy = sinon.spy();
const replaceSpy = sinon.spy();
const component = shallowRender(
{
seedPhrase: '鼠 牛 虎 兔 龍 蛇 馬 羊 猴 雞 狗 豬',
history: { replace: replaceSpy },
setSeedPhraseBackedUp: () => Promise.resolve(),
},
{
trackEvent: trackEventSpy,
},
);
const sorted = component.state().sortedSeedWords;
const seeds = component.find('.confirm-seed-phrase__seed-word--sorted');
const history = {
replace: jest.fn(),
};
const { queryByTestId } = shallowRender({
seedPhrase,
history,
});
originalSeed.forEach((seed) => {
const seedIndex = sorted.findIndex((s) => s === seed);
seeds.at(seedIndex).simulate('click');
fireEvent.click(queryByTestId(`draggable-seed-${seed}`));
});
component.update();
const confirmSeedPhrase = queryByTestId('confirm-dragged-seed-phrase');
fireEvent.click(confirmSeedPhrase);
component.find('.first-time-flow__button').simulate('click');
await new Promise((resolve) => setTimeout(resolve, 100));
expect(trackEventSpy.args[0][0]).toStrictEqual({
category: 'Onboarding',
event: 'Wallet Created',
properties: {
account_type: 'metamask',
is_backup_skipped: false,
},
await waitFor(() => {
expect(history.replace).toHaveBeenCalledWith('/initialize/end-of-flow');
});
expect(replaceSpy.args[0][0]).toStrictEqual('/initialize/end-of-flow');
});
});

View File

@ -198,6 +198,7 @@ export default class ConfirmSeedPhrase extends PureComponent {
</div>
<Button
type="primary"
data-testid="confirm-dragged-seed-phrase"
className="first-time-flow__button"
onClick={this.handleSubmit}
disabled={!this.isValid()}

View File

@ -0,0 +1,541 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Add Recipient Component Domain Resolution should match snapshot 1`] = `
<div>
<div
class="send__select-recipient-wrapper"
>
<div
class="send__select-recipient-wrapper__group-item"
>
<div
class=""
>
<div
class="identicon"
style="height: 28px; width: 28px; border-radius: 14px;"
>
<div
style="border-radius: 50px; overflow: hidden; padding: 0px; margin: 0px; width: 28px; height: 28px; display: inline-block; background: rgb(24, 151, 242);"
>
<svg
height="28"
width="28"
x="0"
y="0"
>
<rect
fill="#2362E1"
height="28"
transform="translate(3.140663911693453 -4.667521795329333) rotate(458.4 14 14)"
width="28"
x="0"
y="0"
/>
<rect
fill="#F94301"
height="28"
transform="translate(-13.443026878443934 6.993307681050803) rotate(268.8 14 14)"
width="28"
x="0"
y="0"
/>
<rect
fill="#FA7900"
height="28"
transform="translate(-7.941722319388745 25.795013895597954) rotate(117.3 14 14)"
width="28"
x="0"
y="0"
/>
</svg>
</div>
</div>
</div>
<div
class="send__select-recipient-wrapper__group-item__content"
>
<div
class="send__select-recipient-wrapper__group-item__title"
>
DNS Re...tion
</div>
</div>
</div>
</div>
</div>
`;
exports[`Add Recipient Component Own Account Recipient Search should match snapshot 1`] = `
<div>
<div
class="send__select-recipient-wrapper"
>
<div
class="send__select-recipient-wrapper__list"
>
<a
class="button btn-link send__select-recipient-wrapper__list__link"
role="button"
tabindex="0"
>
<svg
class="send__select-recipient-wrapper__list__back-caret"
fill="currentColor"
height="24"
viewBox="0 0 512 512"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="m335 113c8 8 8 22 0 30l-113 113 113 113c8 8 8 22 0 30-8 8-22 8-30 0l-128-128c-8-8-8-22 0-30l128-128c8-8 22-8 30 0z"
/>
</svg>
Back to all
</a>
<div
class="send__select-recipient-wrapper__group"
data-testid="recipient-group"
>
<div
class="send__select-recipient-wrapper__group-label"
>
My accounts
</div>
<div
class="send__select-recipient-wrapper__group-item"
>
<div
class=""
>
<div
class="identicon"
style="height: 28px; width: 28px; border-radius: 14px;"
>
<div
style="border-radius: 50px; overflow: hidden; padding: 0px; margin: 0px; width: 28px; height: 28px; display: inline-block; background: rgb(250, 58, 0);"
>
<svg
height="28"
width="28"
x="0"
y="0"
>
<rect
fill="#18CDF2"
height="28"
transform="translate(-0.9173443158196976 -2.8912485607779366) rotate(328.9 14 14)"
width="28"
x="0"
y="0"
/>
<rect
fill="#035E56"
height="28"
transform="translate(-16.01115399522804 9.268404137780026) rotate(176.2 14 14)"
width="28"
x="0"
y="0"
/>
<rect
fill="#F26602"
height="28"
transform="translate(14.584361765945934 -12.429497257622447) rotate(468.9 14 14)"
width="28"
x="0"
y="0"
/>
</svg>
</div>
</div>
</div>
<div
class="send__select-recipient-wrapper__group-item__content"
data-testid="recipient"
>
<div
class="send__select-recipient-wrapper__group-item__title"
>
Test Account
</div>
<div
class="send__select-recipient-wrapper__group-item__subtitle"
>
0x0dcd...e7bc
</div>
</div>
</div>
<div
class="send__select-recipient-wrapper__group-item"
>
<div
class=""
>
<div
class="identicon"
style="height: 28px; width: 28px; border-radius: 14px;"
>
<div
style="border-radius: 50px; overflow: hidden; padding: 0px; margin: 0px; width: 28px; height: 28px; display: inline-block; background: rgb(245, 143, 0);"
>
<svg
height="28"
width="28"
x="0"
y="0"
>
<rect
fill="#018E74"
height="28"
transform="translate(5.524091896954402 -4.749745570944453) rotate(358.4 14 14)"
width="28"
x="0"
y="0"
/>
<rect
fill="#18CAF2"
height="28"
transform="translate(6.724913619395038 -10.621076649467508) rotate(414.8 14 14)"
width="28"
x="0"
y="0"
/>
<rect
fill="#C81474"
height="28"
transform="translate(-4.907795154940259 -21.945972385956175) rotate(322.3 14 14)"
width="28"
x="0"
y="0"
/>
</svg>
</div>
</div>
</div>
<div
class="send__select-recipient-wrapper__group-item__content"
data-testid="recipient"
>
<div
class="send__select-recipient-wrapper__group-item__title"
>
Test Account 2
</div>
<div
class="send__select-recipient-wrapper__group-item__subtitle"
>
0xec1a...251b
</div>
</div>
</div>
<div
class="send__select-recipient-wrapper__group-item"
>
<div
class=""
>
<div
class="identicon"
style="height: 28px; width: 28px; border-radius: 14px;"
>
<div
style="border-radius: 50px; overflow: hidden; padding: 0px; margin: 0px; width: 28px; height: 28px; display: inline-block; background: rgb(249, 100, 1);"
>
<svg
height="28"
width="28"
x="0"
y="0"
>
<rect
fill="#C81432"
height="28"
transform="translate(-0.510690249475231 -2.7159619403490534) rotate(331.7 14 14)"
width="28"
x="0"
y="0"
/>
<rect
fill="#187AF2"
height="28"
transform="translate(-11.127931122273568 5.54021528290869) rotate(160.5 14 14)"
width="28"
x="0"
y="0"
/>
<rect
fill="#FB183E"
height="28"
transform="translate(25.084575445435807 -2.611206239472919) rotate(517.6 14 14)"
width="28"
x="0"
y="0"
/>
</svg>
</div>
</div>
</div>
<div
class="send__select-recipient-wrapper__group-item__content"
data-testid="recipient"
>
<div
class="send__select-recipient-wrapper__group-item__title"
>
Test Ledger 1
</div>
<div
class="send__select-recipient-wrapper__group-item__subtitle"
>
0xc42e...8813
</div>
</div>
</div>
<div
class="send__select-recipient-wrapper__group-item"
>
<div
class=""
>
<div
class="identicon"
style="height: 28px; width: 28px; border-radius: 14px;"
>
<div
style="border-radius: 50px; overflow: hidden; padding: 0px; margin: 0px; width: 28px; height: 28px; display: inline-block; background: rgb(242, 206, 2);"
>
<svg
height="28"
width="28"
x="0"
y="0"
>
<rect
fill="#2340E1"
height="28"
transform="translate(-1.7054541409645272 -0.893781972900803) rotate(257.0 14 14)"
width="28"
x="0"
y="0"
/>
<rect
fill="#016D8E"
height="28"
transform="translate(11.213543194590896 2.66257866392058) rotate(77.0 14 14)"
width="28"
x="0"
y="0"
/>
<rect
fill="#F5F500"
height="28"
transform="translate(11.486654880888956 -19.46641853277226) rotate(465.0 14 14)"
width="28"
x="0"
y="0"
/>
</svg>
</div>
</div>
</div>
<div
class="send__select-recipient-wrapper__group-item__content"
data-testid="recipient"
>
<div
class="send__select-recipient-wrapper__group-item__title"
>
Test Account 3
</div>
<div
class="send__select-recipient-wrapper__group-item__subtitle"
>
0xeb9e...4823
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`Add Recipient Component Send State should match snapshot 1`] = `
<div>
<div
class="send__select-recipient-wrapper"
>
<div
class="send__select-recipient-wrapper__group-item"
>
<div
class=""
>
<div
class="identicon"
style="height: 28px; width: 28px; border-radius: 14px;"
>
<div
style="border-radius: 50px; overflow: hidden; padding: 0px; margin: 0px; width: 28px; height: 28px; display: inline-block; background: rgb(245, 143, 0);"
>
<svg
height="28"
width="28"
x="0"
y="0"
>
<rect
fill="#018E74"
height="28"
transform="translate(5.524091896954402 -4.749745570944453) rotate(358.4 14 14)"
width="28"
x="0"
y="0"
/>
<rect
fill="#18CAF2"
height="28"
transform="translate(6.724913619395038 -10.621076649467508) rotate(414.8 14 14)"
width="28"
x="0"
y="0"
/>
<rect
fill="#C81474"
height="28"
transform="translate(-4.907795154940259 -21.945972385956175) rotate(322.3 14 14)"
width="28"
x="0"
y="0"
/>
</svg>
</div>
</div>
</div>
<div
class="send__select-recipient-wrapper__group-item__content"
>
<div
class="send__select-recipient-wrapper__group-item__title"
>
A
c
c
o
u
n
t
2
</div>
<div
class="send__select-recipient-wrapper__group-item__subtitle"
>
0xec1a...251b
</div>
</div>
</div>
</div>
</div>
`;
exports[`Add Recipient Component render should match snapshot 1`] = `
<div>
<div
class="send__select-recipient-wrapper"
>
<div
class="send__select-recipient-wrapper__list"
>
<div
class="send__select-recipient-wrapper__list"
>
<a
class="button btn-link send__select-recipient-wrapper__list__link"
role="button"
tabindex="0"
>
Transfer between my accounts
</a>
<div
class="send__select-recipient-wrapper__recent-group-wrapper"
/>
<div
class="send__select-recipient-wrapper__group"
data-testid="recipient-group"
>
<div
class="send__select-recipient-wrapper__group-label"
>
A
</div>
<div
class="send__select-recipient-wrapper__group-item"
>
<div
class=""
>
<div
class="identicon"
style="height: 28px; width: 28px; border-radius: 14px;"
>
<div
style="border-radius: 50px; overflow: hidden; padding: 0px; margin: 0px; width: 28px; height: 28px; display: inline-block; background: rgb(249, 100, 1);"
>
<svg
height="28"
width="28"
x="0"
y="0"
>
<rect
fill="#C81432"
height="28"
transform="translate(-0.510690249475231 -2.7159619403490534) rotate(331.7 14 14)"
width="28"
x="0"
y="0"
/>
<rect
fill="#187AF2"
height="28"
transform="translate(-11.127931122273568 5.54021528290869) rotate(160.5 14 14)"
width="28"
x="0"
y="0"
/>
<rect
fill="#FB183E"
height="28"
transform="translate(25.084575445435807 -2.611206239472919) rotate(517.6 14 14)"
width="28"
x="0"
y="0"
/>
</svg>
</div>
</div>
</div>
<div
class="send__select-recipient-wrapper__group-item__content"
data-testid="recipient"
>
<div
class="send__select-recipient-wrapper__group-item__title"
>
Address Book Account 1
</div>
<div
class="send__select-recipient-wrapper__group-item__subtitle"
>
0xc42e...8813
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;

View File

@ -1,178 +1,61 @@
import React from 'react';
import { shallow } from 'enzyme';
import sinon from 'sinon';
import Dialog from '../../../../components/ui/dialog';
import AddRecipient from './add-recipient.component';
const propsMethodSpies = {
updateRecipient: sinon.spy(),
useMyAccountsForRecipientSearch: sinon.spy(),
useContactListForRecipientSearch: sinon.spy(),
};
describe('AddRecipient Component', () => {
let wrapper;
beforeEach(() => {
wrapper = shallow(
<AddRecipient
userInput=""
recipient={{
address: '',
nickname: '',
error: '',
warning: '',
}}
updateSendTo={propsMethodSpies.updateSendTo}
updateSendToError={propsMethodSpies.updateSendToError}
updateSendToWarning={propsMethodSpies.updateSendToWarning}
addressBook={[
{
address: '0x80F061544cC398520615B5d3e7A3BedD70cd4510',
name: 'Fav 5',
},
]}
nonContacts={[
{
address: '0x70F061544cC398520615B5d3e7A3BedD70cd4510',
name: 'Fav 7',
},
]}
contacts={[
{
address: '0x60F061544cC398520615B5d3e7A3BedD70cd4510',
name: 'Fav 6',
},
]}
/>,
{ context: { t: (str) => `${str}_t` } },
);
});
afterEach(() => {
propsMethodSpies.updateRecipient.resetHistory();
propsMethodSpies.useMyAccountsForRecipientSearch.resetHistory();
propsMethodSpies.useContactListForRecipientSearch.resetHistory();
});
import configureMockStore from 'redux-mock-store';
import { renderWithProvider } from '../../../../../test/lib/render-helpers';
import mockState from '../../../../../test/data/mock-state.json';
import mockSendState from '../../../../../test/data/mock-send-state.json';
import AddRecipient from '.';
describe('Add Recipient Component', () => {
describe('render', () => {
it('should render a component', () => {
expect(wrapper.find('.send__select-recipient-wrapper')).toHaveLength(1);
const mockStore = configureMockStore()(mockState);
it('should match snapshot', () => {
const { container } = renderWithProvider(<AddRecipient />, mockStore);
expect(container).toMatchSnapshot();
});
});
it('should render no content if there are no recents, transfers, and contacts', () => {
wrapper.setProps({
ownedAccounts: [],
addressBook: [],
describe('Send State', () => {
const mockStore = configureMockStore()(mockSendState);
it('should match snapshot', () => {
const { container } = renderWithProvider(<AddRecipient />, mockStore);
expect(container).toMatchSnapshot();
});
});
expect(
wrapper.find('.send__select-recipient-wrapper__list__link'),
).toHaveLength(0);
expect(
wrapper.find('.send__select-recipient-wrapper__group'),
).toHaveLength(0);
describe('Domain Resolution', () => {
const mockDomainResolutionState = {
...mockState,
DNS: {
resolution: 'DNS Resolution',
},
};
const mockStore = configureMockStore()(mockDomainResolutionState);
it('should match snapshot', () => {
const { container } = renderWithProvider(<AddRecipient />, mockStore);
expect(container).toMatchSnapshot();
});
});
it('should render transfer', () => {
wrapper.setProps({
isUsingMyAccountsForRecipientSearch: true,
ownedAccounts: [
{ address: '0x123', name: '123' },
{ address: '0x124', name: '124' },
],
addressBook: [{ address: '0x456', name: 'test-name' }],
});
wrapper.setState({ isShowingTransfer: true });
describe('Own Account Recipient Search', () => {
const ownAccountSeachState = {
...mockState,
send: {
...mockState.send,
recipientInput: 'Test',
recipientMode: 'MY_ACCOUNTS',
},
};
const mockStore = configureMockStore()(ownAccountSeachState);
const xferLink = wrapper.find(
'.send__select-recipient-wrapper__list__link',
);
expect(xferLink).toHaveLength(1);
it('should match snapshot', () => {
const { container } = renderWithProvider(<AddRecipient />, mockStore);
const groups = wrapper.find('RecipientGroup');
expect(
groups.shallow().find('.send__select-recipient-wrapper__group'),
).toHaveLength(1);
});
it('should render ContactList', () => {
wrapper.setProps({
ownedAccounts: [
{ address: '0x123', name: '123' },
{ address: '0x124', name: '124' },
],
addressBook: [{ address: '0x125' }],
});
const contactList = wrapper.find('ContactList');
expect(contactList).toHaveLength(1);
});
it('should render contacts', () => {
wrapper.setProps({
addressBook: [
{ address: '0x125', name: 'alice' },
{ address: '0x126', name: 'alex' },
{ address: '0x127', name: 'catherine' },
],
});
wrapper.setState({ isShowingTransfer: false });
const xferLink = wrapper.find(
'.send__select-recipient-wrapper__list__link',
);
expect(xferLink).toHaveLength(0);
const groups = wrapper.find('ContactList');
expect(groups).toHaveLength(1);
expect(
groups.find('.send__select-recipient-wrapper__group-item'),
).toHaveLength(0);
});
it('should render error when query has no results', () => {
wrapper.setProps({
addressBook: [],
domainError: 'bad',
contacts: [],
nonContacts: [],
});
const dialog = wrapper.find(Dialog);
expect(dialog.props().type).toStrictEqual('error');
expect(dialog.props().children).toStrictEqual('bad_t');
expect(dialog).toHaveLength(1);
});
it('should render error when query has ens does not resolve', () => {
wrapper.setProps({
addressBook: [],
domainError: 'very bad',
contacts: [],
nonContacts: [],
});
const dialog = wrapper.find(Dialog);
expect(dialog.props().type).toStrictEqual('error');
expect(dialog.props().children).toStrictEqual('very bad_t');
expect(dialog).toHaveLength(1);
});
it('should render error when ens resolved but ens error exists', () => {
wrapper.setProps({
addressBook: [],
domainError: 'bad',
domainResolution: '0x128',
});
const dialog = wrapper.find(Dialog);
expect(dialog).toHaveLength(1);
expect(container).toMatchSnapshot();
});
});
});