UNPKG

wix-style-react

Version:
713 lines (648 loc) • 27.2 kB
import React from 'react'; import { createRendererWithDriver, createRendererWithUniDriver, cleanup, } from '../../test/utils/react'; import { Table } from './Table'; import { tablePrivateUniDriverFactory } from './Table.private.uni.driver'; import { tableTestkitFactory } from '../../testkit'; import { tablePrivateDriverFactory } from './Table.private.driver'; describe('Table', () => { const ID_1 = 'aaa', ID_2 = 'bbb'; const defaultProps = { id: 'id', data: [ { id: ID_1, a: 'value 1', b: 'value 2' }, { id: ID_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', showSelection: true, children: <Table.Content />, }; const noneSelected = () => []; const firstSelected = () => [ID_1]; const secondSelected = () => [ID_2]; const allSelected = () => [ID_1, ID_2]; describe('[sync]', () => { runTests(createRendererWithDriver(tablePrivateDriverFactory)); }); describe('[async]', () => { runTests(createRendererWithUniDriver(tablePrivateUniDriverFactory)); }); function runTests(render) { afterEach(() => cleanup()); it('should render the table', async () => { const { driver } = render(<Table {...defaultProps} />); expect(await driver.getRowsCount()).toBe(2); expect(await driver.getCellTextValue(0, 1)).toBe('0'); expect(await driver.getCellTextValue(0, 2)).toBe(defaultProps.data[0].a); expect(await driver.getCellTextValue(0, 3)).toBe(defaultProps.data[0].b); expect(await driver.getCellTextValue(1, 1)).toBe('1'); expect(await driver.getCellTextValue(1, 2)).toBe(defaultProps.data[1].a); expect(await driver.getCellTextValue(1, 3)).toBe(defaultProps.data[1].b); }); it('should pass id prop to child', async () => { const { driver } = render(<Table {...defaultProps} />); expect(await driver.hasChildWithId(defaultProps.id)).toBe(true); }); describe('showSelection prop', () => { it('should display selection column', async () => { const { driver } = render( <Table {...defaultProps} selectedIds={firstSelected()} />, ); const rowCheckboxDriver = await driver.getRowCheckboxDriver(1); expect(await rowCheckboxDriver.exists()).toBe(true); const bulkSelectionCheckboxDriver = await driver.getBulkSelectionCheckboxDriver(); expect(await bulkSelectionCheckboxDriver.exists()).toBe(true); }); it('should not display selection column', async () => { const { driver } = render( <Table {...defaultProps} showSelection={false} />, ); const rowCheckboxDriver = await driver.getRowCheckboxDriver(1); expect(await rowCheckboxDriver.exists()).toBe(false); const bulkSelectionCheckboxDriver = await driver.getBulkSelectionCheckboxDriver(); expect(await bulkSelectionCheckboxDriver.exists()).toBe(false); }); }); describe('unselectable prop', () => { it('should not display selection checkbox when row.unselectable is true', async () => { const { data, ...otherDefaultProps } = defaultProps; const dataWithUnselectable = [ { a: 'value 3', b: 'value 4', unselectable: true }, ...data, ]; const { driver } = render( <Table data={dataWithUnselectable} {...otherDefaultProps} />, ); const firstRowCheckboxDriver = await driver.getRowCheckboxDriver(0); expect(await firstRowCheckboxDriver.exists()).toBe(false); const secondRowCheckboxDriver = await driver.getRowCheckboxDriver(1); expect(await secondRowCheckboxDriver.exists()).toBe(true); }); }); describe('hideBulkSelectionCheckbox prop', () => { it('should display selection checkbox in header by default', async () => { const { driver } = render( <Table {...defaultProps} selectedIds={firstSelected()} />, ); const rowCheckboxDriver = await driver.getRowCheckboxDriver(1); expect(await rowCheckboxDriver.exists()).toBe(true); const bulkSelectionCheckboxDriver = await driver.getBulkSelectionCheckboxDriver(); expect(await bulkSelectionCheckboxDriver.exists()).toBe(true); }); it('should not display selection checkbox in header when set to true', async () => { const { driver } = render( <Table {...defaultProps} hideBulkSelectionCheckbox />, ); const rowCheckboxDriver = await driver.getRowCheckboxDriver(1); expect(await rowCheckboxDriver.exists()).toBe(true); const bulkSelectionCheckboxDriver = await driver.getBulkSelectionCheckboxDriver(); expect(await bulkSelectionCheckboxDriver.exists()).toBe(false); }); }); describe('selectedIds prop', () => { it('should select rows according to selectedIds prop given string ids', async () => { const { driver } = render( <Table {...defaultProps} selectedIds={firstSelected()} />, ); expect(await driver.isRowSelected(0)).toBe(true); expect(await driver.isRowSelected(1)).toBe(false); }); it('should select rows according to selectedIds prop given numeric ids', async () => { const { driver } = render( <Table {...defaultProps} data={[ { id: 1111, a: 'value 1', b: 'value 2' }, { id: 2222, a: 'value 3', b: 'value 4' }, ]} selectedIds={[1111]} />, ); expect(await driver.isRowSelected(0)).toBe(true); expect(await driver.isRowSelected(1)).toBe(false); }); it('should select rows according to selectedIds prop given row index as ids', async () => { const { driver } = render( <Table {...defaultProps} data={[ { a: 'value 1', b: 'value 2' }, { a: 'value 3', b: 'value 4' }, ]} selectedIds={[0]} />, ); expect(await driver.isRowSelected(0)).toBe(true); expect(await driver.isRowSelected(1)).toBe(false); }); it('should update selection if selection prop has change', async () => { const selectedIds = []; const { driver, rerender } = render( <Table {...defaultProps} selectedIds={selectedIds} />, ); expect(await driver.isRowSelected(0)).toBe(false); rerender(<Table {...defaultProps} selectedIds={firstSelected()} />); expect(await driver.isRowSelected(0)).toBe(true); }); }); describe('setSelectedIds', () => { it('should select rows when setSelectedIds is called', async () => { let tableInst; const { driver } = render( <Table {...defaultProps} selectedIds={noneSelected()} ref={c => (tableInst = c)} />, ); expect(await driver.isRowSelected(0)).toBe(false); expect(await driver.isRowSelected(1)).toBe(false); tableInst.setSelectedIds(allSelected()); expect(await driver.isRowSelected(0)).toBe(true); expect(await driver.isRowSelected(1)).toBe(true); }); }); describe('row selection', () => { it('should select row when checkbox clicked given row not selected', async () => { const { driver } = render( <Table {...defaultProps} selectedIds={firstSelected()} />, ); await driver.clickRowCheckbox(1); expect(await driver.isRowSelected(1)).toBe(true); }); it('should unselect row when checkbox clicked given row selected', async () => { const { driver } = render( <Table {...defaultProps} selectedIds={allSelected()} />, ); await driver.clickRowCheckbox(1); expect(await driver.isRowSelected(1)).toBe(false); }); it(`should disable bulk selection when passed 'selectionDisabled' prop`, async () => { const { driver } = render( <Table {...defaultProps} selectionDisabled />, ); expect(await driver.isBulkSelectionDisabled()).toBe(true); }); it(`should disable bulk selection when no item is selectable`, async () => { const { driver } = render( <Table {...defaultProps} selectionDisabled={() => true} />, ); expect(await driver.isBulkSelectionDisabled()).toBe(true); }); it(`should not disable bulk selection when some items are selectable`, async () => { const { driver } = render( <Table {...defaultProps} selectionDisabled={rowData => rowData.id === ID_1} />, ); expect(await driver.isBulkSelectionDisabled()).toBe(false); }); it(`should disable row selection when passed 'selectionDisabled' prop`, async () => { const { driver } = render( <Table {...defaultProps} selectionDisabled />, ); expect(await driver.isRowSelectionDisabled(0)).toBe(true); }); it(`should disable row selection when passed selectionDisabled true`, async () => { const { driver } = render( <Table {...defaultProps} selectedIds={[]} selectionDisabled />, ); await driver.clickRowCheckbox(0); expect(await driver.isRowSelected(0)).toBe(false); }); describe('when passed selectionDisabled prop as function', () => { let tableProps; const selectionDisabled = rowData => rowData.id === ID_1; beforeEach(() => { tableProps = { ...defaultProps, selectionDisabled: selectionDisabled, }; }); it(`should disable checkboxes that match 'selectionDisabled' prop`, async () => { const { driver } = render(<Table {...tableProps} />); expect(await driver.isRowSelectionDisabled(0)).toBe(true); expect(await driver.isRowSelectionDisabled(1)).toBe(false); }); it(`should disable row selection when it matches 'selectionDisabled' prop`, async () => { const { driver } = render(<Table {...tableProps} />); await driver.clickRowCheckbox(0); expect(await driver.isRowSelected(0)).toBe(false); }); it(`should not disable row selection when it does not match 'selectionDisabled' prop`, async () => { const { driver } = render(<Table {...tableProps} />); await driver.clickRowCheckbox(1); expect(await driver.isRowSelected(1)).toBe(true); }); }); describe('tooltip on checkbox', () => { it('should not be displayed if checkboxTooltipContent is not passed', async () => { const { driver } = render(<Table {...defaultProps} />); expect(await driver.isSelectionTooltipEnabled(0)).toBe(false); }); it('should be displayed if checkboxTooltipContent returns a truthy value', async () => { const tooltipContent = 'some tooltip content'; const props = { ...defaultProps }; props.data[1].checkboxTooltipContent = tooltipContent; const { driver } = render(<Table {...props} />); expect(await driver.isSelectionTooltipEnabled(1)).toBe(true); }); it('should display with content of returned value from checkboxTooltipContent', async () => { const tooltipContent = 'some tooltip content'; const props = { ...defaultProps }; props.data[1].checkboxTooltipContent = tooltipContent; const { driver } = render(<Table {...props} />); expect(await driver.getSelectionTooltipContent(1)).toBe( tooltipContent, ); }); }); }); describe('re-render', () => { it('should re-render on data update', async () => { const props = { id: 'id', columns: [ { title: 'Row Num', render: (row, rowNum) => rowNum }, { title: 'A', render: row => row.a }, { title: 'B', render: row => row.b }, ], rowClass: 'class-name', }; const data = [ { a: 'value 1', b: 'value 2' }, { a: 'value 3', b: 'value 4' }, ]; const { driver, rerender } = render(<Table {...props} data={data} />); const newValue = 'value 1 changed'; const COLUMN_A_INDEX = 1; const ROW_INDEX = 0; data[ROW_INDEX].a = newValue; rerender(<Table {...props} data={data} />); expect(await driver.getCellTextValue(ROW_INDEX, COLUMN_A_INDEX)).toBe( newValue, ); }); it('should keep selection when re-rendered given selectedIds not provided (Uncontrolled)', async () => { const { driver, rerender } = render(<Table {...defaultProps} />); expect(await driver.isRowSelected(1)).toBe(false); await driver.clickRowCheckbox(1); expect(await driver.isRowSelected(1)).toBe(true); rerender(<Table {...defaultProps} />); expect(await driver.isRowSelected(1)).toBe(true); }); }); describe('BulkSelection', () => { describe('initial render', () => { it('should display bulk-selection as checked when all rows are selected', async () => { const selectedIds = allSelected(); const { driver } = render( <Table {...defaultProps} selectedIds={selectedIds} />, ); expect((await driver.getBulkSelectionState()) === 'ALL').toBe(true); expect((await driver.getBulkSelectionState()) === 'NONE').toBe(false); expect((await driver.getBulkSelectionState()) === 'SOME').toBe(false); }); it('should display bulk-selection as unchecked when no rows are selected', async () => { const selectedIds = noneSelected(); const { driver } = render( <Table {...defaultProps} selectedIds={selectedIds} />, ); expect((await driver.getBulkSelectionState()) === 'NONE').toBe(true); expect((await driver.getBulkSelectionState()) === 'ALL').toBe(false); }); it('should display bulk-selection as partial when some rows are selected', async () => { const selectedIds = secondSelected(); const { driver } = render( <Table {...defaultProps} selectedIds={selectedIds} />, ); expect((await driver.getBulkSelectionState()) === 'SOME').toBe(true); }); it('should display bulk-selection as checked when data and selectedIds change', async () => { const { driver, rerender } = render( <Table {...defaultProps} data={[{ id: ID_1, a: 'value 1', b: 'value 2' }]} selectedIds={[ID_1]} />, ); expect((await driver.getBulkSelectionState()) === 'ALL').toBe(true); rerender( <Table {...defaultProps} data={[ { id: ID_1, a: 'value 1', b: 'value 2' }, { id: ID_2, a: 'value 3', b: 'value 4' }, ]} selectedIds={[ID_1, ID_2]} />, ); expect((await driver.getBulkSelectionState()) === 'ALL').toBe(true); }); }); describe('Update row selection', () => { it('should select all rows when bulk-selection checkbox clicked given no checkboxes are checked', async () => { const selectedIds = noneSelected(); const { driver } = render( <Table {...defaultProps} selectedIds={selectedIds} />, ); await driver.clickBulkSelectionCheckbox(); expect(await driver.isRowSelected(0)).toBe(true); expect(await driver.isRowSelected(1)).toBe(true); }); it('should select only selectable rows when bulk-selection checkbox clicked given no checkboxes are checked', async () => { const { data, ...otherDefaultProps } = defaultProps; const dataWithUnselectable = [ { a: 'value 3', b: 'value 4', unselectable: true }, ...data, ]; let tableSelectionContext; const { driver } = render( <Table data={dataWithUnselectable} selectedIds={noneSelected()} {...otherDefaultProps} > <Table.ToolbarContainer> {selectionContext => { tableSelectionContext = selectionContext; return null; }} </Table.ToolbarContainer> <Table.Content /> </Table>, ); await driver.clickBulkSelectionCheckbox(); expect(await driver.isRowSelected(1)).toBe(true); expect(await driver.isRowSelected(2)).toBe(true); expect(tableSelectionContext.selectedCount).toBe(data.length); expect(tableSelectionContext.bulkSelectionState).toBe('ALL'); expect(tableSelectionContext.getSelectedIds()).toEqual( data.map(row => row.id), ); }); it('should select all rows when bulk-selection checkbox clicked given some checkboxes are checked', async () => { const selectedIds = secondSelected(); const { driver } = render( <Table {...defaultProps} selectedIds={selectedIds} />, ); await driver.clickBulkSelectionCheckbox(); expect(await driver.isRowSelected(0)).toBe(true); expect(await driver.isRowSelected(1)).toBe(true); }); it('should unselect all rows when bulk-selection checkbox clicked given all checkboxes are checked', async () => { const selectedIds = allSelected(); const { driver } = render( <Table {...defaultProps} selectedIds={selectedIds} />, ); await driver.clickBulkSelectionCheckbox(); expect(await driver.isRowSelected(0)).toBe(false); expect(await driver.isRowSelected(1)).toBe(false); }); }); describe('onSelectionChanged', () => { it('should call onSelectionChanged when bulk-selection checkbox clicked given none selected', async () => { const onSelectionChanged = jest.fn(); const selectedIds = noneSelected(); const { driver } = render( <Table {...defaultProps} selectedIds={selectedIds} onSelectionChanged={onSelectionChanged} />, ); await driver.clickBulkSelectionCheckbox(); expect(onSelectionChanged).toHaveBeenCalledWith(allSelected(), { type: 'ALL', origin: 'TableBulkSelectionCheckbox', }); }); it('should call onSelectionChanged when bulk-selection checkbox clicked given all selected', async () => { const onSelectionChanged = jest.fn(); const selectedIds = allSelected(); const { driver } = render( <Table {...defaultProps} selectedIds={selectedIds} onSelectionChanged={onSelectionChanged} />, ); await driver.clickBulkSelectionCheckbox(); expect(onSelectionChanged).toHaveBeenCalledWith(noneSelected(), { type: 'NONE', origin: 'TableBulkSelectionCheckbox', }); }); it('should call onSelectionChanged when row selected given no checkboxes are checked', async () => { const onSelectionChanged = jest.fn(); const selectedIds = firstSelected(); const { driver } = render( <Table {...defaultProps} selectedIds={selectedIds} onSelectionChanged={onSelectionChanged} />, ); await driver.clickRowCheckbox(1); expect(onSelectionChanged.mock.calls).toHaveLength(1); expect(onSelectionChanged).toHaveBeenCalledWith(allSelected(), { type: 'SINGLE_TOGGLE', id: ID_2, origin: 'Checkbox', value: true, }); }); }); describe('Update BulkSelection', () => { it('should check bulk-selection checkbox when all rows change to check', async () => { const selectedIds = secondSelected(); const { driver } = render( <Table {...defaultProps} selectedIds={selectedIds} />, ); await driver.clickRowCheckbox(0); expect((await driver.getBulkSelectionState()) === 'ALL').toBe(true); }); it('should uncheck bulk-selection checkbox when all rows change to not-selected', async () => { const selectedIds = secondSelected(); const { driver } = render( <Table {...defaultProps} selectedIds={selectedIds} />, ); await driver.clickRowCheckbox(1); expect((await driver.getBulkSelectionState()) === 'NONE').toBe(true); }); it('should uncheck bulk-selection checkbox when deselectRowsByDefault', async () => { const selectedIds = secondSelected(); const { driver } = render( <Table {...defaultProps} deselectRowsByDefault selectedIds={selectedIds} />, ); await driver.clickBulkSelectionCheckbox(); expect((await driver.getBulkSelectionState()) === 'NONE').toBe(true); }); it('should show partial in bulk-selection checkbox when row unselected given all rows selected', async () => { const selectedIds = allSelected(); const { driver } = render( <Table {...defaultProps} selectedIds={selectedIds} />, ); await driver.clickRowCheckbox(1); expect((await driver.getBulkSelectionState()) === 'SOME').toBe(true); }); it('should show partial in bulk-selection checkbox when row selected given all rows not selected', async () => { const selectedIds = noneSelected(); const { driver } = render( <Table {...defaultProps} selectedIds={selectedIds} />, ); await driver.clickRowCheckbox(1); expect((await driver.getBulkSelectionState()) === 'SOME').toBe(true); }); }); }); describe('Compound components', () => { it('should NOT have any compound components', async () => { const { driver } = render( <Table {...defaultProps} showSelection selectedIds={noneSelected()} />, ); expect(!!(await driver.getTitlebar())).toBe(false); }); it('should have Table.ToolbarContainer with SelectionContext', async () => { let toggle; const { driver } = render( <Table {...defaultProps} showSelection selectedIds={allSelected()}> <Table.ToolbarContainer> {({ selectedCount, toggleSelectionById }) => { toggle = toggleSelectionById; return <div>{`${selectedCount} Selected`}</div>; }} </Table.ToolbarContainer> <Table.Content /> </Table>, ); expect(await driver.getInnerHtml()).toMatch('2 Selected'); toggle(ID_1); expect(await driver.getInnerHtml()).toMatch('1 Selected'); }); it('should enable passing origin to SelectionContext methods', async () => { let selectionContext; const onSelectionChanged = jest.fn(); const { driver } = render( <Table {...defaultProps} showSelection selectedIds={noneSelected()} onSelectionChanged={onSelectionChanged} > <Table.ToolbarContainer> {bulkSelectionContext => { selectionContext = bulkSelectionContext; return ( <div>{`${bulkSelectionContext.selectedCount} Selected`}</div> ); }} </Table.ToolbarContainer> <Table.Content /> </Table>, ); selectionContext.toggleSelectionById( ID_1, 'toggleSelectionById origin', ); expect(onSelectionChanged).toHaveBeenCalledWith(firstSelected(), { type: 'SINGLE_TOGGLE', id: ID_1, origin: 'toggleSelectionById origin', value: true, }); selectionContext.selectAll('selectAll origin'); expect(onSelectionChanged).toHaveBeenCalledWith(allSelected(), { type: 'ALL', origin: 'selectAll origin', }); selectionContext.deselectAll('deselectAll origin'); expect(onSelectionChanged).toHaveBeenCalledWith(noneSelected(), { type: 'NONE', origin: 'deselectAll origin', }); selectionContext.toggleAll(false, 'toggleAll origin'); expect(onSelectionChanged).toHaveBeenCalledWith(allSelected(), { type: 'ALL', origin: 'toggleAll origin', }); }); it('should have Table.Titlebar', async () => { const { driver } = render( <Table {...defaultProps} showSelection selectedIds={allSelected()}> <div> <Table.Titlebar /> </div> <div> <Table.Content titleBarVisible={false} /> </div> </Table>, ); expect(!!(await driver.getTitlebar())).toBe(true); }); }); describe('withWrapper', () => { afterEach(() => cleanup()); it('should have working test drivers when without wrapper', async () => { const { container } = render( <Table {...defaultProps} showSelection selectedIds={allSelected()} withWrapper={false} > <div> <div> <Table.Titlebar dataHook="test-table-titlebar" /> </div> <div> <Table.Content titleBarVisible={false} dataHook="test-table-content" /> </div> </div> </Table>, ); const titlebarDriver = tableTestkitFactory({ wrapper: container, dataHook: 'test-table-titlebar', }); const bulkSelectionCheckboxDriver = await titlebarDriver.getBulkSelectionCheckboxDriver(); expect(await bulkSelectionCheckboxDriver.isChecked()).toBe(true); const contentDriver = tableTestkitFactory({ wrapper: container, dataHook: 'test-table-content', }); expect(await contentDriver.exists()).toBe(true); expect(await contentDriver.getRowsCount()).toBe( defaultProps.data.length, ); expect(await contentDriver.isRowSelected(0)).toBe(true); }); }); } });