Skip to content

Commit

Permalink
test(Table): added unit tests to Table components
Browse files Browse the repository at this point in the history
  • Loading branch information
Kirill Kharitonov committed Jan 31, 2024
1 parent 8f2f07b commit c593e24
Show file tree
Hide file tree
Showing 5 changed files with 1,209 additions and 2 deletions.
137 changes: 137 additions & 0 deletions src/components/Table/__tests__/Table.hocs.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import React from 'react';

import {render} from '@testing-library/react';

import {Table, type TableProps} from '../Table';
import {
type WithTableActionsProps,
type WithTableSelectionProps,
type WithTableSettingsProps,
type WithTableSortingProps,
withTableActions,
withTableCopy,
withTableSelection,
withTableSettings,
withTableSorting,
} from '../hoc';

interface Model {
disabled: boolean;
}

function getTextContent(html = '') {
return html.replace(/uniq\d+/g, '');
}

describe('Table HOCs tests', () => {
it('withTableActions should match snapshot', () => {
const Table1 = withTableActions<Model>(Table);

type Props = TableProps<Model> & WithTableActionsProps<Model>;
const props: Props = {
data: [{disabled: false}, {disabled: true}],
columns: [{id: 'name'}],
isRowDisabled: ({disabled}) => disabled,
getRowActions: () => [],
};
const {container} = render(React.createElement<Props>(Table1, props));

expect(container).toMatchSnapshot();
});

it('all HOCs should match snapshot', () => {
const Table1 = withTableSorting(
withTableSettings(withTableCopy(withTableActions(withTableSelection<Model>(Table)))),
);

type Props = TableProps<Model> &
WithTableActionsProps<Model> &
WithTableSelectionProps<Model> &
WithTableSettingsProps &
WithTableSortingProps;

const props: Props = {
data: [{disabled: false}, {disabled: true}],
columns: [{id: 'name'}],
isRowDisabled: ({disabled}) => disabled,
selectedIds: [],
onSelectionChange: () => {},
getRowActions: () => [],
updateSettings: () => Promise.resolve(),
settings: [],
};
const {container} = render(React.createElement<Props>(Table1, props));

expect(container).toMatchSnapshot();
});

it('using withTableActions and withTableSelection should not depend of order', () => {
const Table1 = withTableActions(withTableSelection<Model>(Table));
const Table2 = withTableSelection(withTableActions<Model>(Table));

type Props = TableProps<Model> &
WithTableActionsProps<Model> &
WithTableSelectionProps<Model>;
const props: Props = {
data: [{disabled: false}, {disabled: true}],
columns: [{id: 'name'}],
isRowDisabled: ({disabled}) => disabled,
selectedIds: [],
onSelectionChange: () => {},
getRowActions: () => [],
};
const {container: container1} = render(React.createElement<Props>(Table1, props));
const {container: container2} = render(React.createElement<Props>(Table2, props));

expect(getTextContent(container1.outerHTML)).toEqual(getTextContent(container2.outerHTML));
});

it('using withTableActions and withTableSorting should not depend of order', () => {
const Table1 = withTableActions(withTableSorting<Model>(Table));
const Table2 = withTableSorting(withTableActions<Model>(Table));

type Props = TableProps<Model> & WithTableActionsProps<Model> & WithTableSortingProps;
const props: Props = {
data: [{disabled: false}, {disabled: true}],
columns: [{id: 'name'}],
isRowDisabled: ({disabled}) => disabled,
getRowActions: () => [],
};
const {container: container1} = render(React.createElement<Props>(Table1, props));
const {container: container2} = render(React.createElement<Props>(Table2, props));

expect(getTextContent(container1.outerHTML)).toEqual(getTextContent(container2.outerHTML));
});

it('using all HOCs should not depend of order', () => {
const Table1 = withTableSorting(
withTableSettings(
withTableCopy(withTableActions(withTableSelection<Model, {}>(Table))),
),
);
const Table2 = withTableSelection(
withTableActions(withTableCopy(withTableSettings(withTableSorting<Model, {}>(Table)))),
);

type Props = TableProps<Model> &
WithTableActionsProps<Model> &
WithTableSelectionProps<Model> &
WithTableSettingsProps &
WithTableSortingProps;

const props: Props = {
data: [{disabled: false}, {disabled: true}],
columns: [{id: 'name'}],
isRowDisabled: ({disabled}) => disabled,
selectedIds: [],
onSelectionChange: () => {},
getRowActions: () => [],
updateSettings: () => Promise.resolve(),
settings: [],
};
const {container: container1} = render(React.createElement<Props>(Table1, props));
const {container: container2} = render(React.createElement<Props>(Table2, props));

expect(getTextContent(container1.outerHTML)).toEqual(getTextContent(container2.outerHTML));
});
});
217 changes: 215 additions & 2 deletions src/components/Table/__tests__/Table.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import React from 'react';
import {render, screen, within} from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import {Table, TableProps} from '../Table';
import {Table, TableColumnConfig, TableProps} from '../Table';

import {columns, data} from './utils';
import {DataItem, columns, data} from './utils';

const qaId = 'table-component';

Expand All @@ -19,6 +19,75 @@ describe('Table', () => {
expect(rows.length).toBe(data.length + 1);
});

test('should render empty state', () => {
const props: TableProps<DataItem> = {data: [], columns: [{id: 'name'}]};
const {container} = render(React.createElement<TableProps<DataItem>>(Table, props));

expect(container).toMatchSnapshot();
});

test('should correctly apply `align` prop', () => {
const props: TableProps<{}> = {
data: [{}],
columns: [
{id: 'name1', align: 'left'},
{id: 'name2', align: 'right'},
{id: 'name3', align: 'center'},
],
};
const {container} = render(React.createElement<TableProps<{}>>(Table, props));

expect(container).toMatchSnapshot();
});

test('should correctly apply `width` prop', () => {
const props: TableProps<{}> = {
data: [{}],
columns: [
{id: 'name1', width: 100},
{id: 'name2', width: 200},
{id: 'name3', width: 300},
],
};
const {container} = render(React.createElement<TableProps<{}>>(Table, props));

expect(container).toMatchSnapshot();
});

test('should correctly apply `primary` prop', () => {
const props: TableProps<{}> = {
data: [{}],
columns: [{id: 'name1', primary: true}, {id: 'name2', primary: false}, {id: 'name3'}],
};
const {container} = render(React.createElement<TableProps<{}>>(Table, props));

expect(container).toMatchSnapshot();
});

test('should correctly add custom row classnames', () => {
const props: TableProps<{}> = {
data: [{}],
columns: [{id: 'name'}],
getRowClassNames: () => ['custom-row', 'custom-row_mod'],
};
const {container} = render(React.createElement<TableProps<{}>>(Table, props));

expect(container).toMatchSnapshot();
});

test('should correctly add disabled classname', () => {
const props: TableProps<{disabled: boolean}> = {
data: [{disabled: false}, {disabled: true}],
columns: [{id: 'name'}],
isRowDisabled: ({disabled}) => disabled,
};
const {container} = render(
React.createElement<TableProps<{disabled: boolean}>>(Table, props),
);

expect(container).toMatchSnapshot();
});

test.each(new Array<'top' | 'middle'>('top', 'middle'))(
'render with given "%s" vertical align',
(align) => {
Expand Down Expand Up @@ -185,4 +254,148 @@ describe('Table', () => {
expect(row.className.includes('yc-table__row_disabled')).toBe(expectedFlag);
});
});

describe('getRowId static method', () => {
test('should return index by default', () => {
const props: TableProps<DataItem> = {data, columns: []};

expect(Table.getRowId(props, data[0])).toBe('0');
expect(Table.getRowId(props, data[1])).toBe('1');
expect(Table.getRowId(props, data[2])).toBe('2');
});

test('should use prop as function', () => {
const getRowIdMock = jest.fn((item: DataItem) => '__id__' + item.name);
const props: TableProps<DataItem> = {data, columns: [], getRowId: getRowIdMock};
const id = Table.getRowId(props, data[0]);

expect(getRowIdMock).toBeCalled();
expect(id).toBe('__id__' + data[0].name);
});

test('should call function with correct arguments', () => {
const getRowIdMock = jest.fn();
const props: TableProps<DataItem> = {data, columns: [], getRowId: getRowIdMock};

Table.getRowId(props, data[0]);
Table.getRowId(props, data[1]);
Table.getRowId(props, data[2]);

expect(getRowIdMock.mock.calls.length).toBe(3);
expect(getRowIdMock.mock.calls[0]).toEqual([data[0], 0]);
expect(getRowIdMock.mock.calls[1]).toEqual([data[1], 1]);
expect(getRowIdMock.mock.calls[2]).toEqual([data[2], 2]);
});

test('should use prop as object key', () => {
const props: TableProps<DataItem> = {data, columns: [], getRowId: 'name'};

expect(Table.getRowId(props, data[0])).toBe('Nomlanga Compton');
expect(Table.getRowId(props, data[1])).toBe('Paul Hatfield');
expect(Table.getRowId(props, data[2])).toBe('Phelan Daniel');
});

test('should fallback to index on prop as object key', () => {
const props: TableProps<DataItem> = {data, columns: [], getRowId: 'ts'};

expect(Table.getRowId(props, data[0])).toBe('0');
expect(Table.getRowId(props, data[1])).toBe('1');
expect(Table.getRowId(props, data[2])).toBe('2');
});
});

describe('getHeadCellContent static method', () => {
test('should return id prop value by default', () => {
const column: TableColumnConfig<DataItem> = {id: 'name'};
const {container} = render(Table.getHeadCellContent(column) as React.ReactElement);

expect(container).toHaveTextContent('name');
});

test('should use name prop as function', () => {
const nameMock = jest.fn(() => '__name__');
const column: TableColumnConfig<DataItem> = {id: 'name', name: nameMock};
const {container} = render(Table.getHeadCellContent(column) as React.ReactElement);

expect(nameMock).toBeCalled();
expect(container).toHaveTextContent('__name__');
});

test('should call function with correct arguments', () => {
const nameMock = jest.fn(() => '__name__');
const column: TableColumnConfig<DataItem> = {id: 'name', name: nameMock};
Table.getHeadCellContent(column);

expect(nameMock.mock.calls.length).toBe(1);
expect(nameMock.mock.calls[0]).toEqual([]);
});

test('should use name prop as string', () => {
const column: TableColumnConfig<DataItem> = {id: 'name', name: '__name__'};
const {container} = render(Table.getHeadCellContent(column) as React.ReactElement);

expect(container).toHaveTextContent('__name__');
});
});

describe('getBodyCellContent static method', () => {
test('should return dash by default', () => {
const column: TableColumnConfig<DataItem> = {id: '__unknown__'};
const content = Table.getBodyCellContent(column, data[0], 0);

expect(content).toBe('\u2014');
});

test('should return placeholder on empty value', () => {
const column: TableColumnConfig<any> = {id: 'name', placeholder: '-'};
const items = [{id: 'asdf'}, {name: null}, {name: undefined}, {name: ''}];

expect(Table.getBodyCellContent(column, items[0], 0)).toBe('-');
expect(Table.getBodyCellContent(column, items[0], 1)).toBe('-');
expect(Table.getBodyCellContent(column, items[0], 2)).toBe('-');
expect(Table.getBodyCellContent(column, items[0], 3)).toBe('-');
});

test('should use template prop as function', () => {
const templateMock = jest.fn(() => '__content__');
const column: TableColumnConfig<DataItem> = {id: 'name', template: templateMock};
const content = Table.getBodyCellContent(column, data[0], 0);

expect(templateMock).toBeCalled();
expect(content).toBe('__content__');
});

test('should call function with correct arguments', () => {
const templateMock = jest.fn();
const column: TableColumnConfig<DataItem> = {id: 'name', template: templateMock};
Table.getBodyCellContent(column, data[0], 0);
Table.getBodyCellContent(column, data[1], 1);
Table.getBodyCellContent(column, data[2], 2);

expect(templateMock.mock.calls.length).toBe(3);
expect(templateMock.mock.calls[0]).toEqual([data[0], 0]);
expect(templateMock.mock.calls[1]).toEqual([data[1], 1]);
expect(templateMock.mock.calls[2]).toEqual([data[2], 2]);
});

test('should use template prop as object key', () => {
const column1: TableColumnConfig<DataItem> = {id: 'name', template: 'count'};
const column2: TableColumnConfig<DataItem> = {id: 'name', template: 'city'};

expect(Table.getBodyCellContent(column1, data[0], 0)).toBe(82);
expect(Table.getBodyCellContent(column1, data[1], 1)).toBe(51);
expect(Table.getBodyCellContent(column1, data[2], 2)).toBe(10);
expect(Table.getBodyCellContent(column2, data[0], 0)).toBe('Erli');
expect(Table.getBodyCellContent(column2, data[1], 1)).toBe('Campitello di Fassa');
expect(Table.getBodyCellContent(column2, data[2], 2)).toBe('Meugliano');
});

test('should use id prop as object key', () => {
const column: TableColumnConfig<DataItem> = {id: 'name'};

expect(Table.getBodyCellContent(column, data[0], 0)).toBe('Nomlanga Compton');
expect(Table.getBodyCellContent(column, data[1], 1)).toBe('Paul Hatfield');
expect(Table.getBodyCellContent(column, data[2], 2)).toBe('Phelan Daniel');
});
});
});
Loading

0 comments on commit c593e24

Please sign in to comment.