From 1f5964e450a450c493714094730701294b4d8848 Mon Sep 17 00:00:00 2001 From: Thomas Huang Date: Wed, 3 Aug 2022 13:30:43 -0700 Subject: [PATCH] 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 --- test/lib/render-helpers.js | 25 ++-- .../account-menu/account-menu.component.js | 2 + .../app/account-menu/account-menu.test.js | 87 ++++++-------- .../app/dropdowns/network-dropdown.js | 2 + .../app/dropdowns/network-dropdown.test.js | 111 ++++++------------ ui/components/app/menu-droppo.js | 8 +- .../ui/color-indicator/color-indicator.js | 5 +- 7 files changed, 106 insertions(+), 134 deletions(-) diff --git a/test/lib/render-helpers.js b/test/lib/render-helpers.js index 27bc73b7c..3fcc7528b 100644 --- a/test/lib/render-helpers.js +++ b/test/lib/render-helpers.js @@ -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 ? ( - + - {children} + + {children} + - + ) : ( - {children} + + {children} + ); Wrapper.propTypes = { children: PropTypes.node, }; - - return render(component, { wrapper: Wrapper }); + return { + ...render(component, { wrapper: Wrapper }), + history, + }; } export function renderWithLocalization(component) { diff --git a/ui/components/app/account-menu/account-menu.component.js b/ui/components/app/account-menu/account-menu.component.js index 44b68b739..fe339f7ce 100644 --- a/ui/components/app/account-menu/account-menu.component.js +++ b/ui/components/app/account-menu/account-menu.component.js @@ -219,6 +219,7 @@ export default class AccountMenu extends Component { showAccountDetail(identity.address); }} key={identity.address} + data-testid="account-menu__account" >
{isSelected ? ( @@ -230,6 +231,7 @@ export default class AccountMenu extends Component {
{identity.name || ''}
diff --git a/ui/components/app/account-menu/account-menu.test.js b/ui/components/app/account-menu/account-menu.test.js index c8393533c..df511c419 100644 --- a/ui/components/app/account-menu/account-menu.test.js +++ b/ui/components/app/account-menu/account-menu.test.js @@ -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( - - - , - store, - ); + beforeEach(() => { + renderWithProvider(, 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'); }); diff --git a/ui/components/app/dropdowns/network-dropdown.js b/ui/components/app/dropdowns/network-dropdown.js index a19dae151..43706675c 100644 --- a/ui/components/app/dropdowns/network-dropdown.js +++ b/ui/components/app/dropdowns/network-dropdown.js @@ -185,6 +185,7 @@ class NetworkDropdown extends Component { /> { - 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(); + renderWithProvider(, store); }); - it('checks for network droppo class', () => { - expect(wrapper.find('.network-droppo')).toHaveLength(1); + it('should not render menu dropdown when network dropdown is in false state', () => { + const menuDropdown = screen.queryByTestId('menu-dropdown'); + expect(menuDropdown).not.toBeInTheDocument(); }); - it('renders only one child when networkDropdown is false in state', () => { - expect(wrapper.children()).toHaveLength(1); + it('checks for network droppo class', () => { + 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(); - findTestNetworkFirstIndex(wrapper); + beforeEach(() => { + renderWithProvider(, 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(); + beforeEach(() => { + renderWithProvider(, 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); }); }); }); diff --git a/ui/components/app/menu-droppo.js b/ui/components/app/menu-droppo.js index 87ca1e72a..e57df25a7 100644 --- a/ui/components/app/menu-droppo.js +++ b/ui/components/app/menu-droppo.js @@ -25,7 +25,12 @@ export default class MenuDroppoComponent extends Component { const innerStyle = this.props.innerStyle || {}; return ( -
+
{this.props.children}
); @@ -76,6 +81,7 @@ export default class MenuDroppoComponent extends Component {