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

Convert unit test render from enzyme to @testing-library/react. (#15091)

* Use @testing-library/react for account-menu test

* Add testids for account menu accounts and  balances

* Expand render wrapper functionality with metrics provider and router history

* Add testid to menu-droppo-container and menu-droppo

* Add network item nickname testid

* Use @testing-library/react for network dropdown test

* Add color icon testid

* No need for interpolation for testid in menu-droppo
This commit is contained in:
Thomas Huang 2022-08-03 13:30:43 -07:00 committed by GitHub
parent 3b7074bcd8
commit 1f5964e450
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 107 additions and 135 deletions

View File

@ -2,9 +2,11 @@ import React, { useMemo } from 'react';
import { Provider } from 'react-redux';
import { render } from '@testing-library/react';
import { mount, shallow } from 'enzyme';
import { MemoryRouter } from 'react-router-dom';
import { Router, MemoryRouter } from 'react-router-dom';
import PropTypes from 'prop-types';
import { createMemoryHistory } from 'history';
import { I18nContext, LegacyI18nProvider } from '../../ui/contexts/i18n';
import { LegacyMetaMetricsProvider } from '../../ui/contexts/metametrics';
import { getMessage } from '../../ui/helpers/utils/i18n-helper';
import * as en from '../../app/_locales/en/messages.json';
@ -77,25 +79,32 @@ I18nProvider.defaultProps = {
children: undefined,
};
export function renderWithProvider(component, store) {
export function renderWithProvider(component, store, pathname = '/') {
const history = createMemoryHistory({ initialEntries: [pathname] });
const Wrapper = ({ children }) =>
store ? (
<Provider store={store}>
<MemoryRouter initialEntries={['/']} initialIndex={0}>
<Router history={history}>
<I18nProvider currentLocale="en" current={en} en={en}>
<LegacyI18nProvider>{children}</LegacyI18nProvider>
<LegacyI18nProvider>
<LegacyMetaMetricsProvider>{children}</LegacyMetaMetricsProvider>
</LegacyI18nProvider>
</I18nProvider>
</MemoryRouter>
</Router>
</Provider>
) : (
<LegacyI18nProvider>{children}</LegacyI18nProvider>
<LegacyI18nProvider>
<LegacyMetaMetricsProvider>{children}</LegacyMetaMetricsProvider>
</LegacyI18nProvider>
);
Wrapper.propTypes = {
children: PropTypes.node,
};
return render(component, { wrapper: Wrapper });
return {
...render(component, { wrapper: Wrapper }),
history,
};
}
export function renderWithLocalization(component) {

View File

@ -219,6 +219,7 @@ export default class AccountMenu extends Component {
showAccountDetail(identity.address);
}}
key={identity.address}
data-testid="account-menu__account"
>
<div className="account-menu__check-mark">
{isSelected ? (
@ -230,6 +231,7 @@ export default class AccountMenu extends Component {
<div className="account-menu__name">{identity.name || ''}</div>
<UserPreferencedCurrencyDisplay
className="account-menu__balance"
data-testid="account-menu__balance"
value={identity.balance}
type={PRIMARY}
/>

View File

@ -1,14 +1,11 @@
import React from 'react';
import sinon from 'sinon';
import configureMockStore from 'redux-mock-store';
import { Provider } from 'react-redux';
import { mountWithRouter } from '../../../../test/lib/render-helpers';
import Button from '../../ui/button';
import { fireEvent, screen } from '@testing-library/react';
import { renderWithProvider } from '../../../../test/lib/render-helpers';
import AccountMenu from '.';
describe('Account Menu', () => {
let wrapper;
const mockStore = {
metamask: {
provider: {
@ -57,13 +54,8 @@ describe('Account Menu', () => {
},
};
beforeAll(() => {
wrapper = mountWithRouter(
<Provider store={store}>
<AccountMenu.WrappedComponent {...props} />
</Provider>,
store,
);
beforeEach(() => {
renderWithProvider(<AccountMenu.WrappedComponent {...props} />, store);
});
afterEach(() => {
@ -73,58 +65,53 @@ describe('Account Menu', () => {
describe('Render Content', () => {
it('returns account name from identities', () => {
const accountName = wrapper.find('.account-menu__name');
const accountName = screen.queryAllByTestId('account-menu__account');
expect(accountName).toHaveLength(2);
});
it('renders user preference currency display balance from account balance', () => {
const accountBalance = wrapper.find(
'.currency-display-component.account-menu__balance',
);
const accountBalance = screen.queryAllByTestId('account-menu__balance');
expect(accountBalance).toHaveLength(2);
});
it('simulate click', () => {
const click = wrapper.find(
'.account-menu__account.account-menu__item--clickable',
);
click.first().simulate('click');
const click = screen.getAllByTestId('account-menu__account');
fireEvent.click(click[0]);
expect(props.showAccountDetail.calledOnce).toStrictEqual(true);
expect(props.showAccountDetail.getCall(0).args[0]).toStrictEqual('0x00');
});
it('render imported account label', () => {
const importedAccount = wrapper.find('.keyring-label.allcaps');
expect(importedAccount.text()).toStrictEqual('[imported]');
const importedAccount = screen.getByText('Imported');
expect(importedAccount).toBeInTheDocument();
});
});
describe('Log Out', () => {
let logout;
it('logout', () => {
logout = wrapper.find(Button);
expect(logout).toHaveLength(1);
const logout = screen.getByText('Lock');
expect(logout).toBeInTheDocument();
});
it('simulate click', () => {
logout.simulate('click');
const logout = screen.getByText('Lock');
fireEvent.click(logout);
expect(props.lockMetamask.calledOnce).toStrictEqual(true);
expect(props.history.push.getCall(0).args[0]).toStrictEqual('/');
});
});
describe('Create Account', () => {
let createAccount;
it('renders create account item', () => {
createAccount = wrapper.find({ text: 'createAccount' });
expect(createAccount).toHaveLength(1);
const createAccount = screen.getByText('Create Account');
expect(createAccount).toBeInTheDocument();
});
it('calls toggle menu and push new-account route to history', () => {
createAccount.simulate('click');
const createAccount = screen.getByText('Create Account');
fireEvent.click(createAccount);
expect(props.toggleAccountMenu.calledOnce).toStrictEqual(true);
expect(props.history.push.getCall(0).args[0]).toStrictEqual(
'/new-account',
@ -133,15 +120,14 @@ describe('Account Menu', () => {
});
describe('Import Account', () => {
let importAccount;
it('renders import account item', () => {
importAccount = wrapper.find({ text: 'importAccount' });
expect(importAccount).toHaveLength(1);
const importAccount = screen.getByText('Import Account');
expect(importAccount).toBeInTheDocument();
});
it('calls toggle menu and push /new-account/import route to history', () => {
importAccount.simulate('click');
const importAccount = screen.getByText('Import Account');
fireEvent.click(importAccount);
expect(props.toggleAccountMenu.calledOnce).toStrictEqual(true);
expect(props.history.push.getCall(0).args[0]).toStrictEqual(
'/new-account/import',
@ -150,15 +136,14 @@ describe('Account Menu', () => {
});
describe('Connect Hardware Wallet', () => {
let connectHardwareWallet;
it('renders import account item', () => {
connectHardwareWallet = wrapper.find({ text: 'connectHardwareWallet' });
expect(connectHardwareWallet).toHaveLength(1);
const connectHardwareWallet = screen.getByText('Connect Hardware Wallet');
expect(connectHardwareWallet).toBeInTheDocument();
});
it('calls toggle menu and push /new-account/connect route to history', () => {
connectHardwareWallet.simulate('click');
const connectHardwareWallet = screen.getByText('Connect Hardware Wallet');
fireEvent.click(connectHardwareWallet);
expect(props.toggleAccountMenu.calledOnce).toStrictEqual(true);
expect(props.history.push.getCall(0).args[0]).toStrictEqual(
'/new-account/connect',
@ -167,31 +152,29 @@ describe('Account Menu', () => {
});
describe('Support', () => {
let support;
global.platform = { openTab: sinon.spy() };
it('renders import account item', () => {
support = wrapper.find({ text: 'needHelpSubmitTicket' });
expect(support).toHaveLength(1);
const support = screen.getByText('Submit a Ticket');
expect(support).toBeInTheDocument();
});
it('opens support link when clicked', () => {
support = wrapper.find({ text: 'needHelpSubmitTicket' });
support.simulate('click');
const support = screen.getByText('Submit a Ticket');
fireEvent.click(support);
expect(global.platform.openTab.calledOnce).toStrictEqual(true);
});
});
describe('Settings', () => {
let settings;
it('renders import account item', () => {
settings = wrapper.find({ text: 'settings' });
expect(settings).toHaveLength(1);
const settings = screen.getByText('Settings');
expect(settings).toBeInTheDocument();
});
it('calls toggle menu and push /new-account/connect route to history', () => {
settings.simulate('click');
const settings = screen.getByText('Settings');
fireEvent.click(settings);
expect(props.toggleAccountMenu.calledOnce).toStrictEqual(true);
expect(props.history.push.getCall(0).args[0]).toStrictEqual('/settings');
});

View File

@ -185,6 +185,7 @@ class NetworkDropdown extends Component {
/>
<span
className="network-name-item"
data-testid={`${nickname}-network-item`}
style={{
color: isCurrentRpcTarget
? 'var(--color-text-default)'
@ -258,6 +259,7 @@ class NetworkDropdown extends Component {
/>
<span
className="network-name-item"
data-testid={`${network}-network-item`}
style={{
color:
providerType === network

View File

@ -1,15 +1,12 @@
import React from 'react';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import Button from '../../ui/button';
import { mountWithRouter } from '../../../../test/lib/render-helpers';
import ColorIndicator from '../../ui/color-indicator';
import { screen } from '@testing-library/react';
import { renderWithProvider } from '../../../../test/lib/render-helpers';
import { LOCALHOST_RPC_URL } from '../../../../shared/constants/network';
import NetworkDropdown from './network-dropdown';
import { DropdownMenuItem } from './dropdown';
describe('Network Dropdown', () => {
let wrapper;
const createMockStore = configureMockStore([thunk]);
describe('NetworkDropdown in appState in false', () => {
@ -32,15 +29,17 @@ describe('Network Dropdown', () => {
const store = createMockStore(mockState);
beforeEach(() => {
wrapper = mountWithRouter(<NetworkDropdown store={store} />);
renderWithProvider(<NetworkDropdown />, store);
});
it('should not render menu dropdown when network dropdown is in false state', () => {
const menuDropdown = screen.queryByTestId('menu-dropdown');
expect(menuDropdown).not.toBeInTheDocument();
});
it('checks for network droppo class', () => {
expect(wrapper.find('.network-droppo')).toHaveLength(1);
});
it('renders only one child when networkDropdown is false in state', () => {
expect(wrapper.children()).toHaveLength(1);
const networkDropdown = screen.queryByTestId('network-droppo');
expect(networkDropdown).toBeInTheDocument();
});
});
@ -72,82 +71,52 @@ describe('Network Dropdown', () => {
const store = createMockStore(mockState);
let testNetworkIndex = 1;
const findTestNetworkFirstIndex = (_wrapper) => {
let i = 1;
let found = false;
while (!found) {
if (
_wrapper.find(ColorIndicator).at(i).prop('color') === 'icon-muted'
) {
i += 1;
} else {
found = true;
}
}
testNetworkIndex = i;
};
beforeAll(() => {
wrapper = mountWithRouter(<NetworkDropdown store={store} />);
findTestNetworkFirstIndex(wrapper);
beforeEach(() => {
renderWithProvider(<NetworkDropdown />, store);
});
it('checks background color for first ColorIndicator', () => {
const colorIndicator = wrapper.find(ColorIndicator).at(0);
expect(colorIndicator.prop('color')).toStrictEqual('mainnet');
const mainnetColorIndicator = screen.queryByTestId('color-icon-mainnet');
expect(mainnetColorIndicator).toBeInTheDocument();
});
it('checks background color for second ColorIndicator', () => {
// find where test networks start in case there are custom RPCs
const colorIndicator = wrapper.find(ColorIndicator).at(testNetworkIndex);
expect(colorIndicator.prop('color')).toStrictEqual('ropsten');
const ropstenColorIndicator = screen.queryByTestId('color-icon-ropsten');
expect(ropstenColorIndicator).toBeInTheDocument();
});
it('checks background color for third ColorIndicator', () => {
const colorIndicator = wrapper
.find(ColorIndicator)
.at(testNetworkIndex + 1);
expect(colorIndicator.prop('color')).toStrictEqual('kovan');
const kovanColorIndicator = screen.queryByTestId('color-icon-kovan');
expect(kovanColorIndicator).toBeInTheDocument();
});
it('checks background color for fourth ColorIndicator', () => {
const colorIndicator = wrapper
.find(ColorIndicator)
.at(testNetworkIndex + 2);
expect(colorIndicator.prop('color')).toStrictEqual('rinkeby');
const rinkebyColorIndicator = screen.queryByTestId('color-icon-rinkeby');
expect(rinkebyColorIndicator).toBeInTheDocument();
});
it('checks background color for fifth ColorIndicator', () => {
const colorIndicator = wrapper
.find(ColorIndicator)
.at(testNetworkIndex + 3);
expect(colorIndicator.prop('color')).toStrictEqual('goerli');
const goerliColorIndicator = screen.queryByTestId('color-icon-goerli');
expect(goerliColorIndicator).toBeInTheDocument();
});
it('checks background color for sixth ColorIndicator', () => {
const colorIndicator = wrapper
.find(ColorIndicator)
.at(testNetworkIndex + 4);
expect(colorIndicator.prop('color')).toStrictEqual('localhost');
expect(
wrapper
.find(DropdownMenuItem)
.at(testNetworkIndex + 4)
.text(),
).toStrictEqual('✓localhost');
const localhostColorIndicator = screen.queryByTestId(
'color-icon-localhost',
);
expect(localhostColorIndicator).toBeInTheDocument();
});
it('checks that Add Network button is rendered', () => {
expect(wrapper.find(Button).at(0).children().text()).toStrictEqual(
'addNetwork',
);
const addNetworkButton = screen.queryByText('Add Network');
expect(addNetworkButton).toBeInTheDocument();
});
it('shows test networks in the dropdown', () => {
expect(wrapper.find('.network-dropdown-list li')).toHaveLength(8);
const networkItems = screen.queryAllByTestId(/network-item/u);
expect(networkItems).toHaveLength(8);
});
});
@ -178,26 +147,24 @@ describe('Network Dropdown', () => {
const store = createMockStore(mockState);
beforeAll(() => {
wrapper = mountWithRouter(<NetworkDropdown store={store} />);
beforeEach(() => {
renderWithProvider(<NetworkDropdown />, store);
});
it('checks background color for first ColorIndicator', () => {
const colorIndicator = wrapper.find(ColorIndicator).at(0);
expect(colorIndicator.prop('color')).toStrictEqual('mainnet');
expect(wrapper.find(DropdownMenuItem).at(0).text()).toStrictEqual(
'✓mainnet',
);
const mainnetColorIndicator = screen.queryByTestId('color-icon-mainnet');
expect(mainnetColorIndicator).toBeInTheDocument();
});
it('checks that Add Network button is rendered', () => {
expect(wrapper.find(Button).at(0).children().text()).toStrictEqual(
'addNetwork',
);
const addNetworkButton = screen.queryByText('Add Network');
expect(addNetworkButton).toBeInTheDocument();
});
it('does not show test networks in the dropdown', () => {
expect(wrapper.find('.network-dropdown-list li')).toHaveLength(3);
const networkItems = screen.queryAllByTestId(/network-item/u);
expect(networkItems).toHaveLength(3);
});
});
});

View File

@ -25,7 +25,12 @@ export default class MenuDroppoComponent extends Component {
const innerStyle = this.props.innerStyle || {};
return (
<div className="menu-droppo" key="menu-droppo-drawer" style={innerStyle}>
<div
className="menu-droppo"
key="menu-droppo-drawer"
data-testid="menu-droppo"
style={innerStyle}
>
{this.props.children}
</div>
);
@ -76,6 +81,7 @@ export default class MenuDroppoComponent extends Component {
<div
style={baseStyle}
className={`menu-droppo-container ${containerClassName}`}
data-testid={containerClassName}
>
<style>
{`

View File

@ -19,7 +19,10 @@ export default function ColorIndicator({
});
return (
<div className={colorIndicatorClassName}>
<div
className={colorIndicatorClassName}
data-testid={`color-icon-${color}`}
>
{iconClassName ? (
<i className={classnames('color-indicator__icon', iconClassName)} />
) : (