Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor empty state handling across tables; implement tests #302

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
4be5a71
RecsListTable: test empty state with no matching items
gkarat Jun 2, 2022
8c00e2e
RecsListTable: fix shifted empty state width
gkarat Jun 2, 2022
f1c2926
Update package-lock.json
gkarat Jun 2, 2022
86c76c3
Move checkNoMatchState to table.js
gkarat Jun 3, 2022
135bf51
Do not render icon
gkarat Jun 3, 2022
d4ab14b
Refactor ClustersListTable to make empty state be within table
gkarat Jun 3, 2022
6f0c93f
NoMatchinRecs: do not render icon
gkarat Jun 3, 2022
942211c
ClustersListTable: check for the correct no match empty state
gkarat Jun 3, 2022
0d0347d
Refactor ClustersListTable
gkarat Jun 3, 2022
a3444df
Recs and Clusters lists: always render table tag
gkarat Jun 3, 2022
4c4b598
Refactor affecter clusters table
gkarat Jun 3, 2022
ce92137
Unify NoAffectedClusters message
gkarat Jun 3, 2022
df37f16
Check no match in the affected cluster table
gkarat Jun 3, 2022
50a4890
Unify ErrorState message
gkarat Jun 3, 2022
ea76d6b
Parameterize checkEmptyState
gkarat Jun 3, 2022
d684a80
Refactor ClustersListTable and ClusterRules
gkarat Jun 3, 2022
b8f02bb
ClusterRules: check for empty state
gkarat Jun 3, 2022
2d16a13
Remove dot frm noRecsError
gkarat Jun 3, 2022
ed75bbf
Leave TODOs: fix table headers
gkarat Jun 3, 2022
cc28f3c
RecsListTable spec: fix error state check
gkarat Jun 3, 2022
5ad3c54
Fix Cluster spec
gkarat Jun 3, 2022
414bc50
Add TODOs
gkarat Jun 3, 2022
4d1f2c5
Fix lint, remove extra import
gkarat Jun 3, 2022
92881de
Don't check for body in empty states
gkarat Jun 3, 2022
6fb50d3
Create partial test functions for checkEmptyState
gkarat Jun 3, 2022
5c983e4
Make checkRowCounts work with selectable table
gkarat Jun 3, 2022
67c9491
Use ouiaId to take id component
gkarat Jun 3, 2022
4791cbb
Check for 1 row right in checkEmptyState
gkarat Jun 3, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiled-lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"noMatchingRecommendationsTitle": "No matching recommendations found",
"noRecommendations": "The cluster is not affected by any known recommendations",
"noRecommendationsDesc": "No known recommendations affect this cluster.",
"noRecsError": "No recommendations available.",
"noRecsError": "No recommendations available",
"noRecsErrorDesc": "There was an error fetching recommendations for this cluster. Refresh your page to try again.",
"noRecsForClusterListBody": "To get started, create or register your cluster to get recommendations from Insights Advisor.",
"noRecsForClusterListTitle": "No clusters yet",
Expand Down
2 changes: 2 additions & 0 deletions cypress/utils/components.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const DROPDOWN_ITEM = '[data-ouia-component-type="PF4/DropdownItem"]';
const TBODY = 'tbody[role=rowgroup]';
const TOOLBAR_FILTER = '.ins-c-primary-toolbar__filter';
const TABLE = 'table';
const TITLE = '[data-ouia-component-type="PF4/Title"]';

const ouiaId = (id) => `[data-ouia-component-id="${id}"]`;

Expand All @@ -35,4 +36,5 @@ export {
TBODY,
TOOLBAR_FILTER,
TABLE,
TITLE,
};
33 changes: 30 additions & 3 deletions cypress/utils/table.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import _ from 'lodash';

import { ROW, TBODY } from './components';
import { ROW, TABLE, TBODY, TITLE } from './components';

function checkTableHeaders(expectedHeaders) {
/* patternfly/react-table-4.71.16, for some reason, renders extra empty `th` container;
Expand All @@ -18,8 +18,10 @@ function checkTableHeaders(expectedHeaders) {

// TODO fucntion to get rowgroup

function checkRowCounts(n) {
return cy.get('table').find(TBODY).find(ROW).should('have.length', n);
function checkRowCounts(n, isSelectableTable = false) {
return isSelectableTable
? cy.get('table').find(TBODY).should('have.length', n)
: cy.get('table').find(TBODY).find(ROW).should('have.length', n);
}

function columnName2UrlParam(name) {
Expand All @@ -33,9 +35,34 @@ function tableIsSortedBy(columnTitle) {
.should('have.class', 'pf-c-table__sort pf-m-selected');
}

function checkEmptyState(title, checkIcon = false) {
checkRowCounts(1);
cy.get(TABLE)
.find('[ouiaid=empty-state]')
.should('have.length', 1)
.within(() => {
cy.get('.pf-c-empty-state__icon').should(
'have.length',
checkIcon ? 1 : 0
);
cy.get(`h5${TITLE}`).should('have.text', title);
});
}

function checkNoMatchingClusters() {
return checkEmptyState('No matching clusters found');
}

function checkNoMatchingRecs() {
return checkEmptyState('No matching recommendations found');
}

export {
checkTableHeaders,
checkRowCounts,
columnName2UrlParam,
tableIsSortedBy,
checkEmptyState,
checkNoMatchingClusters,
checkNoMatchingRecs,
};
19 changes: 12 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

85 changes: 42 additions & 43 deletions src/Components/AffectedClustersTable/AffectedClustersTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,11 @@ import uniqBy from 'lodash/uniqBy';

import { conditionalFilterType } from '@redhat-cloud-services/frontend-components/ConditionalFilter/conditionalFilterConstants';
import PrimaryToolbar from '@redhat-cloud-services/frontend-components/PrimaryToolbar';
import { EmptyTable } from '@redhat-cloud-services/frontend-components/EmptyTable';
import { TableToolbar } from '@redhat-cloud-services/frontend-components/TableToolbar';
import { DateFormat } from '@redhat-cloud-services/frontend-components/DateFormat';
import {
Card,
CardBody,
Tooltip,
Bullseye,
Pagination,
} from '@patternfly/react-core';
import { Tooltip, Pagination } from '@patternfly/react-core';
import { PaginationVariant } from '@patternfly/react-core/dist/js/components/Pagination/Pagination';
import { Table } from '@patternfly/react-table/dist/js/components/Table/Table';
import { TableBody } from '@patternfly/react-table/dist/js/components/Table/Body';
import { TableHeader } from '@patternfly/react-table/dist/js/components/Table/Header';
import { Table, TableHeader, TableBody } from '@patternfly/react-table';

import {
ErrorState,
Expand Down Expand Up @@ -69,12 +60,17 @@ const AffectedClustersTable = ({ query, rule, afterDisableFn }) => {
clusters that are affected by the rec */
data = { disabled: [], enabled: [] },
} = query;
const rows = data.enabled;
const rows = data?.enabled || [];
const filters = useSelector(({ filters }) => filters.affectedClustersState);
const perPage = filters.limit;
const page = filters.offset / filters.limit + 1;
const allSelected =
filteredRows.length !== 0 && selected.length === filteredRows.length;
const loadingState = isUninitialized || isFetching;
const errorState = isError;
const successState = isSuccess;
const noInput = successState && rows.length === 0;
const noMatch = rows.length > 0 && filteredRows.length === 0;

const updateFilters = (filters) =>
dispatch(updateAffectedClustersFilters(filters));
Expand Down Expand Up @@ -342,7 +338,35 @@ const AffectedClustersTable = ({ query, rule, afterDisableFn }) => {
ouiaId="clusters"
variant="compact"
cells={AFFECTED_CLUSTERS_COLUMNS}
rows={displayedRows}
rows={
errorState || loadingState || noMatch || noInput ? (
[
{
fullWidth: true,
cells: [
{
props: {
colSpan: AFFECTED_CLUSTERS_COLUMNS.length + 1,
},
title: errorState ? (
<ErrorState />
) : loadingState ? (
<Loading />
) : noInput ? (
<NoAffectedClusters />
) : (
<NoMatchingClusters />
),
},
],
},
]
) : successState ? (
displayedRows
) : (
<ErrorState />
)
}
sortBy={{
index: filters.sortIndex,
direction: filters.sortDirection,
Expand All @@ -359,35 +383,7 @@ const AffectedClustersTable = ({ query, rule, afterDisableFn }) => {
]}
>
<TableHeader />
{(isUninitialized || isFetching) && <Loading />}
{isError && (
// TODO: fix crooked message container
<Card id="error-state-message" ouiaId="error-state">
<CardBody>
<ErrorState />
</CardBody>
</Card>
)}
{isSuccess && rows.length === 0 && (
// TODO: fix crooked message container
<Card id="empty-state-message" ouiaId="empty-state">
<CardBody>
<NoAffectedClusters />
</CardBody>
</Card>
)}
{isSuccess &&
rows.length > 0 &&
(filteredRows.length > 0 ? (
<TableBody />
) : (
// TODO: fix crooked message container
<EmptyTable>
<Bullseye>
<NoMatchingClusters />
</Bullseye>
</EmptyTable>
))}
<TableBody />
</Table>
<TableToolbar isFooter className="ins-c-inventory__table--toolbar">
<Pagination
Expand All @@ -411,7 +407,10 @@ AffectedClustersTable.propTypes = {
isUninitialized: PropTypes.bool.isRequired,
isFetching: PropTypes.bool.isRequired,
isSuccess: PropTypes.bool.isRequired,
data: PropTypes.array,
data: PropTypes.shape({
enabled: PropTypes.array,
disabled: PropTypes.array,
}),
}),
rule: PropTypes.object,
afterDisableFn: PropTypes.func,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import {
checkTableHeaders,
checkRowCounts,
tableIsSortedBy,
checkEmptyState,
checkNoMatchingClusters,
} from '../../../cypress/utils/table';
import {
itemsPerPage,
Expand Down Expand Up @@ -112,6 +114,8 @@ describe('test data', () => {
});
});

// TODO: when checking empty state, also check toolbar available and not disabled

describe('non-empty successful affected clusters table', () => {
beforeEach(() => {
mount(
Expand Down Expand Up @@ -477,8 +481,8 @@ describe('non-empty successful affected clusters table', () => {
let sortedNames = _.map(filterData(filters), 'name');
filterApply(filters);
if (sortedNames.length === 0) {
// TODO check empty table view
// TODO headers are displayed
checkNoMatchingClusters();
checkTableHeaders(TABLE_HEADERS);
} else {
cy.get(`td[data-label="Name"]`)
.then(($els) => {
Expand Down Expand Up @@ -514,7 +518,7 @@ describe('non-empty successful affected clusters table', () => {
let sortedNames = _.map(filterData(filters), 'name');
filterApply(filters);
if (sortedNames.length === 0) {
// TODO check empty table view
checkNoMatchingClusters;
} else {
cy.get(`td[data-label="Name"]`)
.then(($els) => {
Expand Down Expand Up @@ -554,8 +558,8 @@ describe('non-empty successful affected clusters table', () => {

it('empty state is displayed when filters do not match any rule', () => {
cy.get('#name-filter').type('Not existing cluster');
// TODO check empty table view
// TODO headers are displayed
checkNoMatchingClusters();
checkTableHeaders(TABLE_HEADERS);
});
});

Expand Down Expand Up @@ -691,9 +695,7 @@ describe('empty successful affected clusters table', () => {
});

it('renders no clusters message', () => {
cy.get('#empty-state-message')
.find('h4')
.should('have.text', 'No clusters');
checkEmptyState('No clusters', true);
});

it('renders table headers', () => {
Expand Down Expand Up @@ -728,8 +730,8 @@ describe('empty failed affected clusters table', () => {
});

it('renders error message', () => {
cy.get('#error-state-message')
.find('h4')
cy.get('[ouiaid="empty-state"]')
.find('h5')
.should('have.text', 'Something went wrong');
});

Expand Down
1 change: 1 addition & 0 deletions src/Components/Cluster/Cluster.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Breadcrumbs from '../Breadcrumbs';
import Main from '@redhat-cloud-services/frontend-components/Main';

export const Cluster = ({ cluster, match }) => {
// TODO: make breadcrumbs take display name from GET /cluster/id/info
return (
<React.Fragment>
<PageHeader className="pf-m-light ins-inventory-detail">
Expand Down
17 changes: 11 additions & 6 deletions src/Components/Cluster/Cluster.spec.ct.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import { Cluster } from './Cluster';
import { Provider } from 'react-redux';
import getStore from '../../Store';
import singleClusterPageReport from '../../../cypress/fixtures/api/insights-results-aggregator/v2/cluster/dcb95bbf-8673-4f3a-a63c-12d4a530aa6f/reports-disabled-false.json';
import { checkRowCounts } from '../../../cypress/utils/table';
import {
checkNoMatchingRecs,
checkRowCounts,
} from '../../../cypress/utils/table';

// selectors
const CLUSTER_HEADER = '#cluster-header';
Expand Down Expand Up @@ -62,7 +65,7 @@ describe('cluster page', () => {
// renders table component
cy.get(RULES_TABLE).should('have.length', 1);
// test how many rows were rendered
checkRowCounts(singleClusterPageReport.report.data.length);
checkRowCounts(singleClusterPageReport.report.data.length, true);
});

it('cluster page in the loading state', () => {
Expand Down Expand Up @@ -90,7 +93,7 @@ describe('cluster page', () => {
cy.get(CLUSTER_HEADER).should('have.length', 1);
// renders table component
cy.get(RULES_TABLE).should('have.length', 1);
cy.get('#loading-skeleton').should('have.length', 1);
cy.ouiaId('loading-skeleton').should('have.length', 1);
});

it('cluster page in the error state', () => {
Expand Down Expand Up @@ -138,7 +141,7 @@ describe('cluster page', () => {
cy.get(FILTER_CHIPS).each(($el) =>
expect($el.text()).to.be.oneOf(['foo bar', 'Low', 'Performance'])
);
checkRowCounts(0);
checkNoMatchingRecs();
});

it('adds additional filters passed by the query parameters №2', () => {
Expand All @@ -161,7 +164,7 @@ describe('cluster page', () => {
'Service Availability',
])
);
checkRowCounts(0);
checkNoMatchingRecs();
});
});

Expand Down Expand Up @@ -206,7 +209,9 @@ describe('Cluster page display name test №1', () => {
<MemoryRouter>
<Intl>
<Provider store={getStore()}>
<Cluster cluster="" match={props.match} />
<Cluster
{...{ ...props, cluster: { ...props.cluster, data: null } }}
/>
</Provider>
</Intl>
</MemoryRouter>
Expand Down
Loading