wix-style-react
Version:
wix-style-react
468 lines (403 loc) • 15.2 kB
JavaScript
import dataTableDriverFactory from './DataTable.driver';
import React from 'react';
import DataTable from './DataTable';
import { createDriverFactory } from 'wix-ui-test-utils/driver-factory';
import { mount } from 'enzyme';
describe('Table', () => {
const createDriver = createDriverFactory(dataTableDriverFactory);
const createDefaultProps = () => ({
id: 'id',
data: [{ a: 'value 1', b: 'value 2' }, { a: 'value 3', b: 'value 4' }],
columns: [
{ title: 'Row Num', render: (row, rowNum) => rowNum },
{ title: 'A', render: row => row.a },
{ title: 'B', render: row => row.b },
],
rowClass: 'class-name',
});
const defaultProps = createDefaultProps();
it('should pass id prop to child', () => {
const driver = createDriver(<DataTable {...defaultProps} />);
expect(driver.hasChildWithId(defaultProps.id)).toBeTruthy();
});
describe('data is empty', () => {
const rowDataHook = 'row-data-hook';
const props = Object.assign({}, defaultProps, {
data: [],
rowDataHook,
});
it('should display nothing', () => {
const driver = createDriver(<DataTable {...props} />);
expect(driver.isDisplayingNothing()).toBeTruthy();
});
it('should count 0 rows', () => {
const driver = createDriver(<DataTable {...props} />);
expect(driver.getRowsCount()).toEqual(0);
});
it('should count 0 rows with class name', () => {
const driver = createDriver(<DataTable {...props} />);
expect(driver.getRowsWithClassCount(defaultProps.rowClass)).toEqual(0);
});
it('should find 0 rows with data-hook', () => {
const driver = createDriver(<DataTable {...props} />);
expect(driver.getRowsWithDataHook(rowDataHook)).toHaveLength(0);
});
it('should not find a row with data-hook', () => {
const driver = createDriver(<DataTable {...props} />);
expect(driver.getRowWithDataHook(rowDataHook)).toEqual(null);
});
it('should not a header only', () => {
const driver = createDriver(<DataTable {...props} />);
expect(driver.isDisplayingHeaderOnly()).toBeFalsy;
});
it('should not a header ', () => {
const driver = createDriver(<DataTable {...props} />);
expect(driver.isDisplayingHeader()).toBeFalsy;
});
it('should not find a child with id', () => {
const driver = createDriver(<DataTable {...props} />);
expect(driver.hasChildWithId(defaultProps.id)).toBeFalsy;
});
// There rest of the driver's methods would throw some error
});
it('should display something when data is non-empty', () => {
const driver = createDriver(<DataTable {...defaultProps} />);
expect(driver.isDisplayingNothing()).toBeFalsy();
});
it('should display header only when data is empty and showHeaderWhenEmpty is true', () => {
const props = {
...defaultProps,
data: [],
showHeaderWhenEmpty: true,
};
const driver = createDriver(<DataTable {...props} />);
expect(driver.isDisplayingHeaderOnly()).toBeTruthy();
});
it('should render column titles', () => {
const driver = createDriver(<DataTable {...defaultProps} />);
expect(driver.getTitles()).toEqual(
defaultProps.columns.map(col => col.title),
);
});
describe('column width', () => {
const columns = [
{ title: 'Row Num', width: '30%', render: (row, rowNum) => rowNum },
{ title: 'A', width: '40px', render: row => row.a },
{ title: 'B', width: '50px', render: row => row.b },
];
it('should apply column.width', () => {
const driver = createDriver(
<DataTable {...defaultProps} columns={columns} />,
);
columns.forEach((column, colIndex) => {
expect(driver.getHeaderCellWidth(colIndex)).toEqual(column.width);
for (let rowIndex = 0; rowIndex < driver.getRowsCount(); rowIndex++) {
expect(driver.getCellWidth(rowIndex, colIndex)).toBe('');
}
});
});
it('should apply column.width when header is hidden', () => {
const driver = createDriver(
<DataTable {...defaultProps} columns={columns} hideHeader />,
);
columns.forEach((column, colIndex) => {
for (let rowIndex = 0; rowIndex < driver.getRowsCount(); rowIndex++) {
if (rowIndex === 0) {
expect(driver.getCellWidth(rowIndex, colIndex)).toEqual(
column.width,
);
} else {
expect(driver.getCellWidth(rowIndex, colIndex)).toBe('');
}
}
});
});
});
it('should display correct amount of rows', () => {
const driver = createDriver(<DataTable {...defaultProps} />);
expect(driver.getRowsCount()).toBe(defaultProps.data.length);
});
it('should render rows', () => {
const driver = createDriver(<DataTable {...defaultProps} />);
expect(driver.getRowText(0)).toEqual(['0', 'value 1', 'value 2']);
expect(driver.getRowText(1)).toEqual(['1', 'value 3', 'value 4']);
});
it('should assign class to rows', () => {
const driver = createDriver(<DataTable {...defaultProps} />);
expect(driver.getRowsWithClassCount(defaultProps.rowClass)).toBe(
defaultProps.data.length,
);
});
it('should assign a dynamic class to rows', () => {
const getClass = rowData => rowData.a.replace(/[\s]+/g, '-');
const driver = createDriver(
<DataTable {...defaultProps} dynamicRowClass={getClass} />,
);
expect(driver.getRowsWithClassCount('value-1')).toBe(1);
expect(driver.getRowsWithClassCount('value-3')).toBe(1);
expect(driver.getRowsWithClassCount(defaultProps.rowClass)).toBe(
defaultProps.data.length,
);
});
it('should assign dataHook to rows', () => {
const rowDataHook = 'row-data-hook';
const props = Object.assign({}, defaultProps, { rowDataHook });
const driver = createDriver(<DataTable {...props} />);
expect(driver.getRowsWithDataHook(rowDataHook)[0].textContent).toBe(
'0value 1value 2',
);
expect(driver.getRowsWithDataHook(rowDataHook)[1].textContent).toBe(
'1value 3value 4',
);
expect(driver.getRowsWithDataHook(rowDataHook)).toHaveLength(
defaultProps.data.length,
);
});
describe('row keys', () => {
const getRowKey = (wrapper, index) =>
wrapper
.find('tbody tr[data-table-row="dataTableRow"]')
.at(index)
.key();
it('should assign data.id as row keys', () => {
const props = createDefaultProps();
props.data[0].id = '000';
props.data[1].id = '111';
const wrapper = mount(<DataTable {...props} />);
expect(getRowKey(wrapper, 0)).toBe('000');
expect(getRowKey(wrapper, 1)).toBe('111');
});
it('should use rowIndex as keys', () => {
const wrapper = mount(<DataTable {...createDefaultProps()} />);
expect(getRowKey(wrapper, 0)).toBe('0');
expect(getRowKey(wrapper, 1)).toBe('1');
});
});
it('should assign a dynamic dataHook to rows', () => {
const calcDataHook = (rowData, rowIndex) =>
`row-index-${rowIndex}-a-${rowData.a.replace(' ', '_')}`;
const props = Object.assign({}, defaultProps, {
rowDataHook: calcDataHook,
});
const driver = createDriver(<DataTable {...props} />);
expect(driver.getRowWithDataHook(`row-index-0-a-value_1`).textContent).toBe(
'0value 1value 2',
);
expect(driver.getRowWithDataHook(`row-index-1-a-value_3`).textContent).toBe(
'1value 3value 4',
);
});
it('should get a row classes', () => {
const getDynamicClass = (rowData, rowNum) =>
rowNum === 1 ? 'rowNum1' : '';
const driver = createDriver(
<DataTable {...defaultProps} dynamicRowClass={getDynamicClass} />,
);
expect(driver.getRowClasses(1).sort()).toEqual(['class-name', 'rowNum1']);
});
it('should hide table header', () => {
const driver = createDriver(<DataTable {...defaultProps} hideHeader />);
expect(driver.isDisplayingHeader()).toBe(false);
});
it('should override default table header styles', () => {
const inlineThStyle = {
thPadding: '1px',
thHeight: '2px',
thFontSize: '3px',
thBorder: '4px',
thColor: 'rgb(18, 52, 86)',
thOpacity: '0.8',
thLetterSpacing: '1.5px',
};
const driver = createDriver(
<DataTable {...defaultProps} {...inlineThStyle} />,
);
expect(driver.getHeaderCellStyle(0)).toEqual(
jasmine.objectContaining({
padding: '1px',
height: '2px',
'font-size': '3px',
border: '4px',
color: 'rgb(18, 52, 86)',
opacity: '0.8',
'letter-spacing': '1.5px',
}),
);
});
it('should override default cell styles', () => {
const clonedProps = Object.assign({}, defaultProps);
clonedProps.columns.push({
title: 'c',
render: () => 'c',
style: {
paddingLeft: '1px',
height: '2px',
width: '100px',
},
});
const driver = createDriver(<DataTable {...clonedProps} />);
expect(driver.getCellStyle(0, 3)).toEqual(
jasmine.objectContaining({
'padding-left': '1px',
height: '2px',
width: '100px',
}),
);
});
describe('clickableDataRow class', () => {
it('should not assign the class to rows by default', () => {
const props = { ...defaultProps };
const driver = createDriver(<DataTable {...props} />);
expect(driver.isRowClickable(0)).toBe(false);
});
it('should assign the class to rows when onRowClick prop is provided', () => {
const props = {
...defaultProps,
onRowClick: jest.fn(),
};
const driver = createDriver(<DataTable {...props} />);
expect(driver.isRowClickable(0)).toBe(true);
});
});
describe('animatedDataRow class', () => {
it('should not assign the class to rows by default', () => {
const props = { ...defaultProps };
const driver = createDriver(<DataTable {...props} />);
expect(driver.isRowAnimated(0)).toBe(false);
});
it('should assign the class to rows when rowDetails prop is provided', () => {
const props = {
...defaultProps,
rowDetails: row => <span>{row.a}</span>,
};
const driver = createDriver(<DataTable {...props} />);
expect(driver.isRowAnimated(0)).toBe(true);
});
});
describe('Row event handlers', () => {
const tests = [
{ handler: 'onRowClick', driverMethod: 'clickRow' },
{ handler: 'onMouseEnterRow', driverMethod: 'mouseEnterRow' },
{ handler: 'onMouseLeaveRow', driverMethod: 'mouseLeaveRow' },
];
tests.forEach(({ handler, driverMethod }) => {
it(`should call ${handler} with row data and index`, () => {
const props = {
...defaultProps,
[handler]: jest.fn(),
};
const driver = createDriver(<DataTable {...props} />);
driver[driverMethod](0);
expect(props[handler]).toBeCalledWith(props.data[0], 0);
driver[driverMethod](1);
expect(props[handler]).toHaveBeenLastCalledWith(props.data[1], 1);
});
});
it('should expand with correct content and collapse', () => {
const animationSpeed = 500;
const props = {
...defaultProps,
rowDetails: row => <span>{row.a}</span>,
};
const driver = createDriver(<DataTable {...props} />);
expect(driver.hasRowDetails(0)).toBe(true);
expect(driver.getRowDetailsText(0)).toBe('');
driver.clickRow(0);
// After clicking content will appear at once
expect(driver.getRowDetailsText(0)).toBe(defaultProps.data[0].a);
driver.clickRow(0);
expect(driver.hasRowDetails(0)).toBe(true);
// When we clicking second time to collapse content will disappear after a while (based on animation speed)
expect(driver.getRowDetailsText(0)).not.toBe('');
return new Promise(resolve => {
setTimeout(() => {
expect(driver.getRowDetailsText(0)).toBe('');
}, animationSpeed);
resolve();
});
});
it('should have correct row count when row details enabled', () => {
const props = {
...defaultProps,
rowDetails: jest.fn(),
};
const driver = createDriver(<DataTable {...props} />);
expect(driver.getRowsCount()).toBe(2);
driver.clickRow(0);
expect(driver.getRowsCount()).toBe(2);
});
});
describe('Sortable column titles', () => {
let props;
beforeEach(() => {
props = {
...defaultProps,
columns: [
{ title: 'Row Num', render: (row, rowNum) => rowNum },
{
title: 'A',
sortable: true,
sortDescending: false,
render: row => row.a,
},
{ title: 'B', render: row => row.b },
{
title: 'C',
sortable: true,
sortDescending: true,
render: row => row.a,
},
],
};
});
it('should display sortable title', () => {
const _props = Object.assign({}, props, { onSortClick: jest.fn() });
const driver = createDriver(<DataTable {..._props} />);
expect(driver.hasSortableTitle(0)).toBe(false);
expect(driver.hasSortableTitle(1)).toBe(true);
});
it('should display sort asc/desc style', () => {
const _props = Object.assign({}, props, { onSortClick: jest.fn() });
const driver = createDriver(<DataTable {..._props} />);
expect(driver.hasSortDescending(1)).toBe(false);
expect(driver.hasSortDescending(3)).toBe(true);
});
it('should display new sort asc/desc style', () => {
const _props = Object.assign({}, props, { onSortClick: jest.fn() });
const driver = createDriver(<DataTable {..._props} newDesign />);
expect(driver.hasNewSortDescending(1)).toBe(false);
expect(driver.hasNewSortDescending(3)).toBe(true);
});
it('should call on sort callback', () => {
const _props = Object.assign({}, props, { onSortClick: jest.fn() });
const driver = createDriver(<DataTable {..._props} />);
driver.clickSort(1);
expect(_props.onSortClick).toBeCalledWith(props.columns[1], 1);
});
it('should not call on sort callback when non-sortable column is clicked', () => {
const _props = Object.assign({}, props, { onSortClick: jest.fn() });
const driver = createDriver(<DataTable {..._props} />);
driver.clickSort(2);
expect(_props.onSortClick).not.toHaveBeenCalled();
});
});
describe('Tooltip titles', () => {
it('should display tooltip icon', () => {
const props = {
...defaultProps,
columns: [
{ title: 'Row Num', render: (row, rowNum) => rowNum },
{
title: 'A',
infoTooltipProps: { content: 'Vary informative tooltip text' },
render: row => row.a,
},
{ title: 'B', render: row => row.b },
],
};
const driver = createDriver(<DataTable {...props} />);
expect(driver.hasInfoIcon(0)).toBe(false);
expect(driver.hasInfoIcon(1)).toBe(true);
});
});
});