diff --git a/.eslintrc.js b/.eslintrc.js index b6094c794e6f..ae8b384bff5b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -129,7 +129,12 @@ module.exports = { }, }, { - files: ['ui/**/*.test.js', 'ui/__mocks__/*.js', 'shared/**/*.test.js'], + files: [ + 'ui/**/*.test.js', + 'ui/__mocks__/*.js', + 'shared/**/*.test.js', + 'test/jest/*.js', + ], extends: ['@metamask/eslint-config-jest'], rules: { 'jest/no-restricted-matchers': 'off', diff --git a/test/jest/index.js b/test/jest/index.js index 098877489808..b68672d34541 100644 --- a/test/jest/index.js +++ b/test/jest/index.js @@ -1,3 +1,5 @@ +import './matchers'; + export { createSwapsMockStore } from './mock-store'; export { renderWithProvider } from './rendering'; export { setBackgroundConnection } from './background'; diff --git a/test/jest/matchers.js b/test/jest/matchers.js new file mode 100644 index 000000000000..660018b40ed0 --- /dev/null +++ b/test/jest/matchers.js @@ -0,0 +1,35 @@ +import { shallow, mount } from 'enzyme'; + +const SHALLOW_WRAPPER_CONSTRUCTOR = 'ShallowWrapper'; + +function isShallowWrapper(wrapper) { + return wrapper.constructor.name + ? wrapper.constructor.name === SHALLOW_WRAPPER_CONSTRUCTOR + : Boolean(`${wrapper.constructor}`.match(/^function ShallowWrapper\(/u)); +} + +function toMatchElement( + actualEnzymeWrapper, + reactInstance, + options = { ignoreProps: true }, +) { + const expectedWrapper = isShallowWrapper(actualEnzymeWrapper) + ? shallow(reactInstance) + : mount(reactInstance); + + const actual = actualEnzymeWrapper.debug({ verbose: true, ...options }); + const expected = expectedWrapper.debug({ verbose: true, ...options }); + const pass = actual === expected; + + return { + pass, + message: 'Expected actual value to match the expected value.', + negatedMessage: 'Did not expect actual value to match the expected value.', + contextualInformation: { + actual: `Actual:\n ${actual}`, + expected: `Expected:\n ${expected}`, + }, + }; +} + +expect.extend({ toMatchElement }); diff --git a/test/jest/setup.js b/test/jest/setup.js index 6176cfc660db..db848f08a8d2 100644 --- a/test/jest/setup.js +++ b/test/jest/setup.js @@ -1,2 +1,3 @@ // This file is for Jest-specific setup only and runs before our Jest tests. import '@testing-library/jest-dom'; +import './matchers'; diff --git a/ui/components/app/contact-list/contact-list.component.js b/ui/components/app/contact-list/contact-list.component.js index 04e3a3abd0a9..713edfcfb98d 100644 --- a/ui/components/app/contact-list/contact-list.component.js +++ b/ui/components/app/contact-list/contact-list.component.js @@ -1,5 +1,6 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; +import { sortBy } from 'lodash'; import Button from '../../ui/button'; import RecipientGroup from './recipient-group/recipient-group.component'; @@ -50,34 +51,36 @@ export default class ContactList extends PureComponent { } renderAddressBook() { - const contacts = this.props.searchForContacts(); + const unsortedContactsByLetter = this.props + .searchForContacts() + .reduce((obj, contact) => { + const firstLetter = contact.name[0].toUpperCase(); + return { + ...obj, + [firstLetter]: [...(obj[firstLetter] || []), contact], + }; + }, {}); - const contactGroups = contacts.reduce((acc, contact) => { - const firstLetter = contact.name.slice(0, 1).toUpperCase(); - acc[firstLetter] = acc[firstLetter] || []; - const bucket = acc[firstLetter]; - bucket.push(contact); - return acc; - }, {}); + const letters = Object.keys(unsortedContactsByLetter).sort(); - return Object.entries(contactGroups) - .sort(([letter1], [letter2]) => { - if (letter1 > letter2) { - return 1; - } else if (letter1 === letter2) { - return 0; - } - return -1; - }) - .map(([letter, groupItems]) => ( - - )); + const sortedContactGroups = letters.map((letter) => { + return [ + letter, + sortBy(unsortedContactsByLetter[letter], (contact) => { + return contact.name.toLowerCase(); + }), + ]; + }); + + return sortedContactGroups.map(([letter, groupItems]) => ( + + )); } renderMyAccounts() { diff --git a/ui/components/app/contact-list/contact-list.test.js b/ui/components/app/contact-list/contact-list.test.js new file mode 100644 index 000000000000..8646cc70d2d3 --- /dev/null +++ b/ui/components/app/contact-list/contact-list.test.js @@ -0,0 +1,60 @@ +import React from 'react'; +import { shallowWithContext } from '../../../../test/lib/render-helpers'; +import RecipientGroup from './recipient-group'; +import ContactList from '.'; + +describe('Contact List', () => { + describe('given searchForContacts', () => { + it('sorts contacts by name within each letter group', () => { + const contacts = { + Al: { name: 'Al', address: '0x0' }, + aa: { name: 'aa', address: '0x1' }, + Az: { name: 'Az', address: '0x2' }, + Bl: { name: 'Bl', address: '0x3' }, + ba: { name: 'ba', address: '0x4' }, + Bz: { name: 'Bz', address: '0x5' }, + Ccc: { name: 'Ccc', address: '0x6' }, + }; + const searchForContacts = () => { + return Object.values(contacts); + }; + const selectRecipient = () => null; + const selectedAddress = null; + + const wrapper = shallowWithContext( + , + ); + + expect(wrapper).toMatchElement( +
+ + + +
, + { ignoreProps: false }, + ); + }); + }); +});