mirror of
https://github.com/ansible/awx.git
synced 2026-01-11 01:57:35 -03:30
flush out tests for PaginatedTable and related components
This commit is contained in:
parent
204af9ec91
commit
a9d7fea86f
@ -0,0 +1,29 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import ActionItem from './ActionItem';
|
||||
|
||||
describe('<ActionItem />', () => {
|
||||
test('should render child with tooltip', async () => {
|
||||
const wrapper = shallow(
|
||||
<ActionItem columns={1} tooltip="a tooltip" visible>
|
||||
foo
|
||||
</ActionItem>
|
||||
);
|
||||
|
||||
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(
|
||||
<ActionItem columns={1} tooltip="foo">
|
||||
<div>foo</div>
|
||||
</ActionItem>
|
||||
);
|
||||
|
||||
expect(wrapper.find('Tooltip')).toHaveLength(0);
|
||||
expect(wrapper.find('div')).toHaveLength(0);
|
||||
expect(wrapper.text()).toEqual('');
|
||||
});
|
||||
});
|
||||
@ -15,6 +15,7 @@ const ActionsGrid = styled.div`
|
||||
`;
|
||||
}}
|
||||
`;
|
||||
ActionsGrid.displayName = 'ActionsGrid';
|
||||
|
||||
export default function ActionsTd({ children, ...props }) {
|
||||
const numActions = children.length || 1;
|
||||
|
||||
@ -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 (
|
||||
<Thead>
|
||||
<Tr>
|
||||
|
||||
65
awx/ui_next/src/components/PaginatedTable/HeaderRow.test.jsx
Normal file
65
awx/ui_next/src/components/PaginatedTable/HeaderRow.test.jsx
Normal file
@ -0,0 +1,65 @@
|
||||
import React from 'react';
|
||||
import { createMemoryHistory } from 'history';
|
||||
import { mountWithContexts } from '../../../testUtils/enzymeHelpers';
|
||||
import HeaderRow, { HeaderCell } from './HeaderRow';
|
||||
|
||||
describe('<HeaderRow />', () => {
|
||||
const qsConfig = {
|
||||
defaultParams: {
|
||||
order_by: 'one',
|
||||
},
|
||||
};
|
||||
|
||||
test('should render cells', async () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<table>
|
||||
<HeaderRow qsConfig={qsConfig}>
|
||||
<HeaderCell sortKey="one">One</HeaderCell>
|
||||
<HeaderCell>Two</HeaderCell>
|
||||
</HeaderRow>
|
||||
</table>
|
||||
);
|
||||
|
||||
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(
|
||||
<table>
|
||||
<HeaderRow qsConfig={qsConfig}>
|
||||
<HeaderCell sortKey="one">One</HeaderCell>
|
||||
<HeaderCell>Two</HeaderCell>
|
||||
</HeaderRow>
|
||||
</table>,
|
||||
{ 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(
|
||||
<table>
|
||||
<HeaderRow qsConfig={qsConfig}>
|
||||
<HeaderCell sortKey="one">One</HeaderCell>
|
||||
<HeaderCell>Two</HeaderCell>
|
||||
</HeaderRow>
|
||||
</table>,
|
||||
{ context: { router: { history } } }
|
||||
);
|
||||
|
||||
const cell = wrapper.find('Th').at(2);
|
||||
expect(cell.prop('sort')).toEqual(null);
|
||||
});
|
||||
});
|
||||
@ -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 => <PaginatedTableRow key={item.id} item={item} />,
|
||||
renderToolbar: props => <DataListToolbar {...props} />,
|
||||
};
|
||||
|
||||
|
||||
@ -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('<PaginatedTable />', () => {
|
||||
test('should render item rows', () => {
|
||||
const history = createMemoryHistory({
|
||||
initialEntries: ['/organizations/1/teams'],
|
||||
});
|
||||
const wrapper = mountWithContexts(
|
||||
<PaginatedTable
|
||||
items={mockData}
|
||||
itemCount={7}
|
||||
queryParams={{
|
||||
page: 1,
|
||||
page_size: 5,
|
||||
order_by: 'name',
|
||||
}}
|
||||
qsConfig={qsConfig}
|
||||
renderRow={item => (
|
||||
<tr key={item.id}>
|
||||
<td>{item.name}</td>
|
||||
</tr>
|
||||
)}
|
||||
/>,
|
||||
{ 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(
|
||||
<PaginatedTable
|
||||
items={mockData}
|
||||
itemCount={7}
|
||||
queryParams={{
|
||||
page: 1,
|
||||
page_size: 5,
|
||||
order_by: 'name',
|
||||
}}
|
||||
qsConfig={qsConfig}
|
||||
renderRow={() => 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(
|
||||
<PaginatedTable
|
||||
items={mockData}
|
||||
itemCount={7}
|
||||
queryParams={{
|
||||
page: 1,
|
||||
page_size: 5,
|
||||
order_by: 'name',
|
||||
}}
|
||||
qsConfig={qsConfig}
|
||||
renderRow={() => 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');
|
||||
});
|
||||
});
|
||||
@ -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 (
|
||||
<DataListItem
|
||||
aria-labelledby={`items-list-item-${item.id}`}
|
||||
key={item.id}
|
||||
id={`${item.id}`}
|
||||
>
|
||||
<DataListItemRow>
|
||||
<DataListItemCells
|
||||
dataListCells={[
|
||||
<DataListCell key="name">
|
||||
<DetailWrapper>
|
||||
<Link to={{ pathname: item.url }}>
|
||||
<b id={`items-list-item-${item.id}`}>{item.name}</b>
|
||||
</Link>
|
||||
</DetailWrapper>
|
||||
</DataListCell>,
|
||||
]}
|
||||
/>
|
||||
</DataListItemRow>
|
||||
</DataListItem>
|
||||
);
|
||||
}
|
||||
@ -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';
|
||||
|
||||
@ -190,7 +190,7 @@ function InventoryList({ i18n }) {
|
||||
toolbarSearchableKeys={searchableKeys}
|
||||
toolbarRelatedSearchableKeys={relatedSearchableKeys}
|
||||
headerRow={
|
||||
<HeaderRow defaultSortKey="name" qsConfig={QS_CONFIG}>
|
||||
<HeaderRow qsConfig={QS_CONFIG}>
|
||||
<HeaderCell sortKey="name">{i18n._(t`Name`)}</HeaderCell>
|
||||
<HeaderCell>{i18n._(t`Status`)}</HeaderCell>
|
||||
<HeaderCell>{i18n._(t`Type`)}</HeaderCell>
|
||||
|
||||
@ -150,7 +150,7 @@ function OrganizationsList({ i18n }) {
|
||||
toolbarSearchableKeys={searchableKeys}
|
||||
toolbarRelatedSearchableKeys={relatedSearchableKeys}
|
||||
headerRow={
|
||||
<HeaderRow defaultSortKey="name" qsConfig={QS_CONFIG}>
|
||||
<HeaderRow qsConfig={QS_CONFIG}>
|
||||
<HeaderCell sortKey="name">{i18n._(t`Name`)}</HeaderCell>
|
||||
<HeaderCell>{i18n._(t`Members`)}</HeaderCell>
|
||||
<HeaderCell>{i18n._(t`Teams`)}</HeaderCell>
|
||||
|
||||
@ -28,15 +28,20 @@ function OrganizationListItem({
|
||||
onSelect,
|
||||
disable: false,
|
||||
}}
|
||||
dataLabel={i18n._(t`Selected`)}
|
||||
/>
|
||||
<Td id={labelId}>
|
||||
<Td id={labelId} dataLabel={i18n._(t`Name`)}>
|
||||
<Link to={`${detailUrl}`}>
|
||||
<b>{organization.name}</b>
|
||||
</Link>
|
||||
</Td>
|
||||
<Td>{organization.summary_fields.related_field_counts.users}</Td>
|
||||
<Td>{organization.summary_fields.related_field_counts.teams}</Td>
|
||||
<ActionsTd>
|
||||
<Td dataLabel={i18n._(t`Members`)}>
|
||||
{organization.summary_fields.related_field_counts.users}
|
||||
</Td>
|
||||
<Td dataLabel={i18n._(t`Teams`)}>
|
||||
{organization.summary_fields.related_field_counts.teams}
|
||||
</Td>
|
||||
<ActionsTd dataLabel={i18n._(t`Actions`)}>
|
||||
<ActionItem
|
||||
visible={organization.summary_fields.user_capabilities.edit}
|
||||
tooltip={i18n._(t`Edit Organization`)}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user