From a9d7fea86f298ac37535690a20f29176726d41b9 Mon Sep 17 00:00:00 2001 From: Keith Grant Date: Thu, 10 Dec 2020 16:10:10 -0800 Subject: [PATCH] flush out tests for PaginatedTable and related components --- .../PaginatedTable/ActionItem.test.jsx | 29 +++++ .../components/PaginatedTable/ActionsTd.jsx | 1 + .../components/PaginatedTable/HeaderRow.jsx | 5 +- .../PaginatedTable/HeaderRow.test.jsx | 65 +++++++++++ .../PaginatedTable/PaginatedTable.jsx | 4 +- .../PaginatedTable/PaginatedTable.test.jsx | 108 ++++++++++++++++++ .../PaginatedTable/PaginatedTableRow.jsx | 42 ------- .../src/components/PaginatedTable/index.js | 1 - .../Inventory/InventoryList/InventoryList.jsx | 2 +- .../OrganizationList/OrganizationList.jsx | 2 +- .../OrganizationList/OrganizationListItem.jsx | 13 ++- 11 files changed, 218 insertions(+), 54 deletions(-) create mode 100644 awx/ui_next/src/components/PaginatedTable/ActionItem.test.jsx create mode 100644 awx/ui_next/src/components/PaginatedTable/HeaderRow.test.jsx create mode 100644 awx/ui_next/src/components/PaginatedTable/PaginatedTable.test.jsx delete mode 100644 awx/ui_next/src/components/PaginatedTable/PaginatedTableRow.jsx diff --git a/awx/ui_next/src/components/PaginatedTable/ActionItem.test.jsx b/awx/ui_next/src/components/PaginatedTable/ActionItem.test.jsx new file mode 100644 index 0000000000..202e556e83 --- /dev/null +++ b/awx/ui_next/src/components/PaginatedTable/ActionItem.test.jsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import ActionItem from './ActionItem'; + +describe('', () => { + test('should render child with tooltip', async () => { + const wrapper = shallow( + + foo + + ); + + const tooltip = wrapper.find('Tooltip'); + expect(tooltip.prop('content')).toEqual('a tooltip'); + expect(tooltip.prop('children')).toEqual('foo'); + }); + + test('should render null if not visible', async () => { + const wrapper = shallow( + +
foo
+
+ ); + + expect(wrapper.find('Tooltip')).toHaveLength(0); + expect(wrapper.find('div')).toHaveLength(0); + expect(wrapper.text()).toEqual(''); + }); +}); diff --git a/awx/ui_next/src/components/PaginatedTable/ActionsTd.jsx b/awx/ui_next/src/components/PaginatedTable/ActionsTd.jsx index 8ed5f74344..f60323da37 100644 --- a/awx/ui_next/src/components/PaginatedTable/ActionsTd.jsx +++ b/awx/ui_next/src/components/PaginatedTable/ActionsTd.jsx @@ -15,6 +15,7 @@ const ActionsGrid = styled.div` `; }} `; +ActionsGrid.displayName = 'ActionsGrid'; export default function ActionsTd({ children, ...props }) { const numActions = children.length || 1; diff --git a/awx/ui_next/src/components/PaginatedTable/HeaderRow.jsx b/awx/ui_next/src/components/PaginatedTable/HeaderRow.jsx index dcb7134487..259cc39bac 100644 --- a/awx/ui_next/src/components/PaginatedTable/HeaderRow.jsx +++ b/awx/ui_next/src/components/PaginatedTable/HeaderRow.jsx @@ -12,7 +12,7 @@ const Th = styled(PFTh)` --pf-c-table--cell--Overflow: initial; `; -export default function HeaderRow({ qsConfig, defaultSortKey, children }) { +export default function HeaderRow({ qsConfig, children }) { const location = useLocation(); const history = useHistory(); @@ -33,10 +33,11 @@ export default function HeaderRow({ qsConfig, defaultSortKey, children }) { const sortKey = params.order_by?.replace('-', ''); const sortBy = { - index: sortKey || defaultSortKey, + index: sortKey || qsConfig.defaultParams?.order_by, direction: params.order_by?.startsWith('-') ? 'desc' : 'asc', }; + // empty first Th aligns with checkboxes in table rows return ( diff --git a/awx/ui_next/src/components/PaginatedTable/HeaderRow.test.jsx b/awx/ui_next/src/components/PaginatedTable/HeaderRow.test.jsx new file mode 100644 index 0000000000..ec1124c4b7 --- /dev/null +++ b/awx/ui_next/src/components/PaginatedTable/HeaderRow.test.jsx @@ -0,0 +1,65 @@ +import React from 'react'; +import { createMemoryHistory } from 'history'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; +import HeaderRow, { HeaderCell } from './HeaderRow'; + +describe('', () => { + const qsConfig = { + defaultParams: { + order_by: 'one', + }, + }; + + test('should render cells', async () => { + const wrapper = mountWithContexts( + + + One + Two + +
+ ); + + const cells = wrapper.find('Th'); + expect(cells).toHaveLength(3); + expect(cells.at(1).text()).toEqual('One'); + expect(cells.at(2).text()).toEqual('Two'); + }); + + test('should provide sort controls', async () => { + const history = createMemoryHistory({ + initialEntries: ['/list'], + }); + const wrapper = mountWithContexts( + + + One + Two + +
, + { context: { router: { history } } } + ); + + const cell = wrapper.find('Th').at(1); + cell.prop('sort').onSort({}, '', 'desc'); + expect(history.location.search).toEqual('?order_by=-one'); + }); + + test('should not sort cells without a sortKey', async () => { + const history = createMemoryHistory({ + initialEntries: ['/list'], + }); + const wrapper = mountWithContexts( + + + One + Two + +
, + { context: { router: { history } } } + ); + + const cell = wrapper.find('Th').at(2); + expect(cell.prop('sort')).toEqual(null); + }); +}); diff --git a/awx/ui_next/src/components/PaginatedTable/PaginatedTable.jsx b/awx/ui_next/src/components/PaginatedTable/PaginatedTable.jsx index 9d5964cd9f..2176bd3b57 100644 --- a/awx/ui_next/src/components/PaginatedTable/PaginatedTable.jsx +++ b/awx/ui_next/src/components/PaginatedTable/PaginatedTable.jsx @@ -17,7 +17,6 @@ import { parseQueryString, replaceParams, } from '../../util/qs'; -import PaginatedTableRow from './PaginatedTableRow'; import { QSConfig, SearchColumns } from '../../types'; function PaginatedTable({ @@ -160,7 +159,7 @@ PaginatedTable.propTypes = { itemCount: PropTypes.number.isRequired, pluralizedItemName: PropTypes.string, qsConfig: QSConfig.isRequired, - renderRow: PropTypes.func, + renderRow: PropTypes.func.isRequired, toolbarSearchColumns: SearchColumns, toolbarSearchableKeys: PropTypes.arrayOf(PropTypes.string), toolbarRelatedSearchableKeys: PropTypes.arrayOf(PropTypes.string), @@ -178,7 +177,6 @@ PaginatedTable.defaultProps = { toolbarRelatedSearchableKeys: [], pluralizedItemName: 'Items', showPageSizeOptions: true, - renderRow: item => , renderToolbar: props => , }; diff --git a/awx/ui_next/src/components/PaginatedTable/PaginatedTable.test.jsx b/awx/ui_next/src/components/PaginatedTable/PaginatedTable.test.jsx new file mode 100644 index 0000000000..29f2222048 --- /dev/null +++ b/awx/ui_next/src/components/PaginatedTable/PaginatedTable.test.jsx @@ -0,0 +1,108 @@ +import React from 'react'; +import { createMemoryHistory } from 'history'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; +import PaginatedTable from './PaginatedTable'; + +const mockData = [ + { id: 1, name: 'one', url: '/org/team/1' }, + { id: 2, name: 'two', url: '/org/team/2' }, + { id: 3, name: 'three', url: '/org/team/3' }, + { id: 4, name: 'four', url: '/org/team/4' }, + { id: 5, name: 'five', url: '/org/team/5' }, +]; + +const qsConfig = { + namespace: 'item', + defaultParams: { page: 1, page_size: 5, order_by: 'name' }, + integerFields: ['page', 'page_size'], +}; + +describe('', () => { + test('should render item rows', () => { + const history = createMemoryHistory({ + initialEntries: ['/organizations/1/teams'], + }); + const wrapper = mountWithContexts( + ( + + {item.name} + + )} + />, + { context: { router: { history } } } + ); + + const rows = wrapper.find('tr'); + expect(rows).toHaveLength(5); + expect(rows.at(0).text()).toEqual('one'); + expect(rows.at(1).text()).toEqual('two'); + expect(rows.at(2).text()).toEqual('three'); + expect(rows.at(3).text()).toEqual('four'); + expect(rows.at(4).text()).toEqual('five'); + }); + + test('should navigate page when changes', () => { + const history = createMemoryHistory({ + initialEntries: ['/organizations/1/teams'], + }); + const wrapper = mountWithContexts( + null} + />, + { context: { router: { history } } } + ); + + const pagination = wrapper.find('Pagination').at(1); + pagination.prop('onSetPage')(null, 2); + expect(history.location.search).toEqual('?item.page=2'); + wrapper.update(); + pagination.prop('onSetPage')(null, 1); + // since page = 1 is the default, that should be strip out of the search + expect(history.location.search).toEqual(''); + }); + + test('should navigate to page when page size changes', () => { + const history = createMemoryHistory({ + initialEntries: ['/organizations/1/teams'], + }); + const wrapper = mountWithContexts( + null} + />, + { context: { router: { history } } } + ); + + const pagination = wrapper.find('Pagination').at(1); + pagination.prop('onPerPageSelect')(null, 25, 2); + expect(history.location.search).toEqual('?item.page=2&item.page_size=25'); + wrapper.update(); + // since page_size = 5 is the default, that should be strip out of the search + pagination.prop('onPerPageSelect')(null, 5, 2); + expect(history.location.search).toEqual('?item.page=2'); + }); +}); diff --git a/awx/ui_next/src/components/PaginatedTable/PaginatedTableRow.jsx b/awx/ui_next/src/components/PaginatedTable/PaginatedTableRow.jsx deleted file mode 100644 index 6db53493cb..0000000000 --- a/awx/ui_next/src/components/PaginatedTable/PaginatedTableRow.jsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react'; -import { Link } from 'react-router-dom'; -import { - DataListItem, - DataListItemRow, - DataListItemCells, - TextContent, -} from '@patternfly/react-core'; -import styled from 'styled-components'; -import DataListCell from '../DataListCell'; - -const DetailWrapper = styled(TextContent)` - display: grid; - grid-template-columns: - minmax(70px, max-content) - repeat(auto-fit, minmax(60px, max-content)); - grid-gap: 10px; -`; - -export default function PaginatedDataListItem({ item }) { - return ( - - - - - - {item.name} - - - , - ]} - /> - - - ); -} diff --git a/awx/ui_next/src/components/PaginatedTable/index.js b/awx/ui_next/src/components/PaginatedTable/index.js index c38bb6acae..f4b1804d9a 100644 --- a/awx/ui_next/src/components/PaginatedTable/index.js +++ b/awx/ui_next/src/components/PaginatedTable/index.js @@ -1,5 +1,4 @@ export { default } from './PaginatedTable'; -export { default as PaginatedTableRow } from './PaginatedTableRow'; export { default as ActionsTd } from './ActionsTd'; export { default as HeaderRow, HeaderCell } from './HeaderRow'; export { default as ActionItem } from './ActionItem'; diff --git a/awx/ui_next/src/screens/Inventory/InventoryList/InventoryList.jsx b/awx/ui_next/src/screens/Inventory/InventoryList/InventoryList.jsx index ce3d936743..c9594e4e17 100644 --- a/awx/ui_next/src/screens/Inventory/InventoryList/InventoryList.jsx +++ b/awx/ui_next/src/screens/Inventory/InventoryList/InventoryList.jsx @@ -190,7 +190,7 @@ function InventoryList({ i18n }) { toolbarSearchableKeys={searchableKeys} toolbarRelatedSearchableKeys={relatedSearchableKeys} headerRow={ - + {i18n._(t`Name`)} {i18n._(t`Status`)} {i18n._(t`Type`)} diff --git a/awx/ui_next/src/screens/Organization/OrganizationList/OrganizationList.jsx b/awx/ui_next/src/screens/Organization/OrganizationList/OrganizationList.jsx index 49ab977167..1be109e533 100644 --- a/awx/ui_next/src/screens/Organization/OrganizationList/OrganizationList.jsx +++ b/awx/ui_next/src/screens/Organization/OrganizationList/OrganizationList.jsx @@ -150,7 +150,7 @@ function OrganizationsList({ i18n }) { toolbarSearchableKeys={searchableKeys} toolbarRelatedSearchableKeys={relatedSearchableKeys} headerRow={ - + {i18n._(t`Name`)} {i18n._(t`Members`)} {i18n._(t`Teams`)} diff --git a/awx/ui_next/src/screens/Organization/OrganizationList/OrganizationListItem.jsx b/awx/ui_next/src/screens/Organization/OrganizationList/OrganizationListItem.jsx index 1db1d7e859..dc727dba47 100644 --- a/awx/ui_next/src/screens/Organization/OrganizationList/OrganizationListItem.jsx +++ b/awx/ui_next/src/screens/Organization/OrganizationList/OrganizationListItem.jsx @@ -28,15 +28,20 @@ function OrganizationListItem({ onSelect, disable: false, }} + dataLabel={i18n._(t`Selected`)} /> - + {organization.name} - {organization.summary_fields.related_field_counts.users} - {organization.summary_fields.related_field_counts.teams} - + + {organization.summary_fields.related_field_counts.users} + + + {organization.summary_fields.related_field_counts.teams} + +