Skip to content

Commit

Permalink
feat(CypressUtils): Docs for cypress and improved doctypes
Browse files Browse the repository at this point in the history
  • Loading branch information
Fewwy committed Nov 1, 2022
1 parent b2f3cf9 commit cb226b8
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 7 deletions.
1 change: 1 addition & 0 deletions packages/utils/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ import parseCvssScore from '@redhat-cloud-services/frontend-components-utilities
* [redux](doc/redux.md)
* [routerParams](doc/routerParams.md)
* [debounce](doc/debounce.md)
* [cypress](doc/cypress.md)
Additionaly it exports these utilities
* AsyncComponent - class to load component via async calls
Expand Down
114 changes: 114 additions & 0 deletions packages/utils/doc/cypress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# Cypress Utility functions

The [cypress](https://www.cypress.io/) library is a great tool that allows to write scalable component tests.

These utility functions are created to create scalable tests utilizing Patternfly UI library.

## Usage
1) Install Cypress v10+ on your project. You can find the documentation [here](https://docs.cypress.io/guides/component-testing/quickstart-react).
2) Go through the installation and setup, then set up the first component test.
3) Add more tests for components utilizing the functions we provide.

### Table Functions
**checkTableHeaders** - Check the table column headers to be equal to provided array of objects with titles. Each title = string.

**checkRowCounts** - Check if the table setting of "rows shown" is equal to the passed number parameter.

**columnName2UrlParam** - Checks the URL for the name of the column which sorting is "active".

**tableIsSortedBy** - Check the table sorting by the passed string parameter.

**checkEmptyState** - Check the empty state message by the passed string parameter.
Optionally checks for the "checkIcon" if you pass true as a second parameter.

### Pagination Functions
**itemsPerPage** - Checks if the table shows the correct number of items per page.

**checkPaginationTotal** - Checks pagination total.

**checkPaginationValues** - Checks pagination dropdown values.

**changePagination** - Changes page limit and check if the URL contains the limit=pagination value
```JS
cy.wrap(PAGINATION_VALUES).each((el) => {
changePagination(el).then(() => {
expect(window.location.search).to.contain(`limit=${el}`);
});
});
```

### Filter Functions
**applyFilters** - Apply a given set of filters taken into account the filters configuration.

**urlParamConvert** - Converts URL parameters to the values and checks if filter chips with such values exists.
```JS
// urlParamConvert filter parameter example
FILTER_CATEGORIES = {
total_risk: {
type: 'checkbox',
title: 'total risk',
urlParam: 'total_risk',
values: [
{ label: TOTAL_RISK_LABEL[4], value: '4' },
{ label: TOTAL_RISK_LABEL[3], value: '3' },
{ label: TOTAL_RISK_LABEL[2], value: '2' },
{ label: TOTAL_RISK_LABEL[1], value: '1' },
],
},
}
// urlParamConvert test example
it('recognizes all parameters', () => {
const urlSearchParameters = new URLSearchParams(urlParams);
for (const [key, value] of urlSearchParameters) {
if (key == 'text') {
hasChip('Name', value);
cy.get('.pf-m-fill > .pf-c-form-control').should('have.value', value);
} else {
value.split(',').forEach((it) => {
const [group, item] = urlParamConvert(key, it, FILTER_CATEGORIES);
hasChip(group, item);
});
}
}
// do not get more chips than expected
cy.get(CHIP_GROUP).should(
'have.length',
Array.from(urlSearchParameters).length
);
});
```

**hasChip** - Checks if the filter chip group contain the chip with the passed name and value.

**filter** - filter data given a set of filter values and their configuration.

**removeAllChips** - Removes all active chips


### Selectors and default values
```
DEFAULT_ROW_COUNT = 20;
PAGINATION_VALUES = [10, 20, 50, 100];
SORTING_ORDERS = ['ascending', 'descending'];
TOOLBAR = 'div[id="ins-primary-data-toolbar"]';
CHIP_GROUP = 'div[data-ouia-component-type="PF4/ChipGroup"]';
CHIP = '[data-ouia-component-type="PF4/Chip"]';
ROW = '[data-ouia-component-type="PF4/TableRow"]:not([class~="pf-c-table__expandable-row"])';
PAGINATION = 'div[data-ouia-component-type="PF4/Pagination"]';
PAGINATION_MENU = 'div[data-ouia-component-type="PF4/PaginationOptionsMenu"]';
DROPDOWN = '[data-ouia-component-type="PF4/Dropdown"]';
MODAL = '[data-ouia-component-type="PF4/ModalContent"]';
CHECKBOX = '[data-ouia-component-type="PF4/Checkbox"]';
TEXT_INPUT = '[data-ouia-component-type="PF4/TextInput"]';
DROPDOWN_TOGGLE = '[data-ouia-component-type="PF4/DropdownToggle"]';
DROPDOWN_ITEM = '[data-ouia-component-type="PF4/DropdownItem"]';
TBODY = 'tbody[role=rowgroup]';
TOOLBAR_FILTER = '.ins-c-primary-toolbar__filter';
TABLE = 'table';
TABLE_HEADER = 'thead';
ROWS_TOGGLER = `${TABLE_HEADER} .pf-c-table__toggle`;
TITLE = '[data-ouia-component-type="PF4/Title"]';
ouiaId = (id) => `[data-ouia-component-id="${id}"]`;
FILTERS_DROPDOWN = 'ul[class=pf-c-dropdown__menu]';
FILTER_TOGGLE = 'button[class=pf-c-select__toggle]';
```
28 changes: 28 additions & 0 deletions packages/utils/src/CypressUtils/PaginationUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ const DEFAULT_ROW_COUNT = 20;
const PAGINATION_VALUES = [10, 20, 50, 100];
const SORTING_ORDERS = ['ascending', 'descending'];

/**
* - Checks if the table shows the correct number of items per page.
* @typedef {Object} itemsPerPage
* @param {number} totalLength - the length of fixtures array e.g. the amount of items overall.
* @param {number} pageSize - "items shown" setting of the table, default is 20.
*/
export function itemsPerPage(totalLength, pageSize = DEFAULT_ROW_COUNT) {
let items = totalLength;
const array = [];
Expand All @@ -17,10 +23,20 @@ export function itemsPerPage(totalLength, pageSize = DEFAULT_ROW_COUNT) {
return array;
}

/**
* - Checks pagination total
* @typedef {Object} checkPaginationTotal
* @param {number} n - the length of fixtures array e.g. the amount of items overall.
*/
export function checkPaginationTotal(n) {
return cy.get('.pf-c-options-menu__toggle-text').find('b').eq(1).should('have.text', n);
}

/**
* - Checks pagination dropdown values
* @typedef {Object} checkPaginationValues
* @param {array} expectedValues - array of strings with pagination values
*/
export function checkPaginationValues(expectedValues) {
cy.get(TOOLBAR).find(PAGINATION_MENU).find(DROPDOWN_TOGGLE).click();
cy.get(TOOLBAR)
Expand All @@ -32,6 +48,18 @@ export function checkPaginationValues(expectedValues) {
});
}

/**
* - Changes page limit and check if the URL contains the limit=pagination value
* @typedef {Object} changePagination
* @param {array} paginationValue - array of strings with pagination values
*
* - Example
* cy.wrap(PAGINATION_VALUES).each((el) => {
* changePagination(el).then(() => {
* expect(window.location.search).to.contain(`limit=${el}`);
* });
* });
*/
export function changePagination(paginationValue) {
cy.get(TOOLBAR).find(PAGINATION_MENU).find(DROPDOWN_TOGGLE).click();
return cy.get(TOOLBAR).find(PAGINATION_MENU).find('ul[class=pf-c-options-menu__menu]').find(DROPDOWN_ITEM).contains(`${paginationValue}`).click();
Expand Down
32 changes: 29 additions & 3 deletions packages/utils/src/CypressUtils/TableUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import _ from 'lodash';

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

/**
* - Check the table column headers to be equal to provided array of objects.
* @typedef {Object} checkTableHeaders
* @param {string} expectedHeaders - Array of objects with titles. Each title = string
*/
export function checkTableHeaders(expectedHeaders) {
/* patternfly/react-table-4.71.16, for some reason, renders extra empty `th` container;
thus, it is necessary to look at the additional `scope` attr to distinguish between visible columns
Expand All @@ -15,18 +20,39 @@ export function checkTableHeaders(expectedHeaders) {
.should('deep.equal', expectedHeaders);
}

/**
* - Check if the table setting of "rows shown" is equal to the passed number parameter.
* @typedef {Object} checkRowCounts
* @param {number} n - number of rows
* @param {boolean} isSelectableTable - selectable table option
*/
export 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);
}

/**
* - Checks the URL for the name of the column which sorting is "active".
* @typedef {Object} columnName2UrlParam
* @param {string} name - column name string
*/
export function columnName2UrlParam(name) {
return name.toLowerCase().replace(/ /g, '_');
}

/**
* - Check the table sorting by the passed string parameter.
* Doesn't work with the sorting on the backend.
* @typedef {Object} tableIsSortedBy
* @param {string} columnTitle - column title string
*/
export function tableIsSortedBy(columnTitle) {
return cy.get('table').find(`th[data-label="${columnTitle}"]`).should('have.class', 'pf-c-table__sort pf-m-selected');
}

/**
* - Check the empty state message by the passed string parameter.
* Optionally checks for the "checkIcon" if you pass true as a second parameter.
* @typedef {Object} checkEmptyState
* @param {string} title
* @param {boolean} checkIcon
*/
export function checkEmptyState(title, checkIcon = false) {
checkRowCounts(1);
cy.get(TABLE)
Expand Down
38 changes: 34 additions & 4 deletions packages/utils/src/CypressUtils/UIFilters.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { CHIP, CHIP_GROUP, FILTERS_DROPDOWN, FILTER_TOGGLE } from './selectors';

/**
* Apply a given set of filters taken into account the filters configuration
* @typedef {Function} applyFilters
* @param {*} filters value to set on the filters
* {key: string (for input/radio) | array (for checkbox)}
* @param {@FiltersConf} - global configuration of the filter settings
Expand Down Expand Up @@ -52,7 +53,27 @@ function applyFilters(filters, filtersConf) {
}
}
}

/**
* - Converts URL parameters to the values and checks if filter chips with such values exists.
* @typedef {Function} urlParamConvert
* @param {string} key - string key of URL parameter
* @param {string} value - string value of URL parameter
* @param {Object} filters - Object that contains filters description.
* - Example of filters parameter
* FILTER_CATEGORIES = {
* total_risk: {
* type: 'checkbox',
* title: 'total risk',
* urlParam: 'total_risk',
* values: [
* { label: TOTAL_RISK_LABEL[4], value: '4' },
* { label: TOTAL_RISK_LABEL[3], value: '3' },
* { label: TOTAL_RISK_LABEL[2], value: '2' },
* { label: TOTAL_RISK_LABEL[1], value: '1' },
* ],
*},
*}
*/
function urlParamConvert(key, value, filters) {
const filterCategory = _.find(_.values(filters), (it) => it.urlParam === key);
let title;
Expand All @@ -66,13 +87,19 @@ function urlParamConvert(key, value, filters) {
}
return [title, label];
}

/**
* - Checks if the filter chip group contain the chip with the passed name and value
* @typedef {Function} hasChip
* @param {string} name
* @param {string} value
*/
function hasChip(name, value) {
cy.contains(CHIP_GROUP, name).parent().contains(CHIP, value);
}
/**
* filter data given a set of filter values and their configuration
* @param {@filtersConf} conf - Configuration of the filters
* @typedef {Function} filter
* @param {filtersConf} conf - Configuration of the filters
* @param {Array} data - Values to be filtered
* @param {Object} filters - Applied filters and their values
* @returns
Expand All @@ -88,7 +115,10 @@ function filter(conf, data, filters) {
}
return filteredData;
}

/**
* - Removes all active chips
* @typedef {Function} removeAllChips
*/
function removeAllChips() {
// FIXME does not work: OCPADVISOR-22
// cy.get(CHIP_GROUP)
Expand Down

0 comments on commit cb226b8

Please sign in to comment.