@salesforce/design-system-react
Version:
Salesforce Lightning Design System for React
1,155 lines (1,002 loc) • 30.6 kB
JSX
/* eslint-disable max-lines */
import React from 'react';
import ReactDOM from 'react-dom';
import TestUtils from 'react-dom/test-utils';
import chai, { expect } from 'chai';
import { keyObjects } from '../../../utilities/key-code';
import Dropdown from '../../menu-dropdown';
import DataTable from '../../data-table';
import DataTableColumn from '../../data-table/column';
import DataTableRowActions from '../../data-table/row-actions';
import DataTableHighlightCell from '../../data-table/highlight-cell';
import IconSettings from '../../icon-settings';
import {
mountComponent,
unmountComponent,
} from '../../../tests/enzyme-helpers';
chai.should();
const { Simulate } = TestUtils;
describe('DataTable: ', function describeFunction() {
const items = [
{
id: '8IKZHZZV80',
name: 'Cloudhub',
count: 100976,
lastModified: 'Yesterday',
},
{
id: '5GJOOOPWU7',
name: 'Cloudhub + Anypoint Connectors',
count: 54976,
lastModified: 'Today',
},
{
id: 'Q8Z71ZUCEZ',
name: 'Cloud City',
count: 101280,
lastModified: 'Today',
},
{
id: '2FSH2DP0LY',
name: 'IoT',
count: 976,
lastModified: 'Yesterday',
},
{
id: '8NE888QKV1',
name: 'IoT + Anypoint Connectors',
count: 54976,
lastModified: 'Today',
},
{
id: 'M4D37GW83H',
name: 'Salesforce Tower',
count: 101280,
lastModified: 'Today',
},
];
const itemsWithHeaderRows = [
{
id: 'K6R34GW73J',
type: 'header-row',
name: 'Address',
count: 101210,
lastModified: 'Today',
},
...items,
{
id: 'KA78KJAY76',
type: 'header-row',
name: 'Company',
count: 101318,
lastModified: 'Today',
},
];
const columns = [
{
label: 'Name',
property: 'name',
truncate: true,
},
{
label: 'Count',
property: 'count',
sortable: true,
},
];
const defaultProps = {
id: 'DataTableExample-default',
items,
selectRows: true,
};
const defaultPropsWithHeaderRows = {
...defaultProps,
items: itemsWithHeaderRows,
};
const renderTable = (instance) =>
function renderTableFunction() {
this.dom = document.createElement('div');
document.body.appendChild(this.dom);
/* deepscan-disable REACT_ASYNC_RENDER_RETURN_VALUE */
// eslint-disable-next-line react/no-render-return-value
this.component = ReactDOM.render(
<div>
<IconSettings iconPath="/assets/icons">{instance}</IconSettings>
</div>,
this.dom
);
/* deepscan-enable REACT_ASYNC_RENDER_RETURN_VALUE */
};
function removeTable() {
ReactDOM.unmountComponentAtNode(this.dom);
document.body.removeChild(this.dom);
}
const getTable = (dom) => dom.querySelector('.slds-table');
const getRow = (dom, row) => {
const tbody = getTable(dom).querySelectorAll('tbody')[0];
return tbody.querySelectorAll('tr')[row - 1];
};
const getCell = (dom, row, column) => {
const tr = getRow(dom, row);
return tr.querySelectorAll('td')[column];
};
const getMenu = (dom) => dom.querySelector('.slds-dropdown');
describe('Structure', function describeFunction2() {
beforeEach(
renderTable(
<DataTable {...defaultProps}>
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
</DataTable>
)
);
afterEach(removeTable);
it('has a header', function () {
const thead = getTable(this.dom).querySelectorAll('thead');
thead.should.have.length(1);
thead[0].querySelectorAll('th').should.have.length(3);
});
it('has a row for each item', function () {
const tbody = getTable(this.dom).querySelectorAll('tbody');
tbody.should.have.length(1);
tbody[0].querySelectorAll('tr').should.have.length(6);
});
it('renders the correct contents in each cell', function () {
const firstName = getCell(this.dom, 1, 1);
firstName.innerHTML.should.equal(
'<div class="" title="Cloudhub">Cloudhub</div>'
);
const secondCount = getCell(this.dom, 2, 2);
secondCount.innerHTML.should.equal(
'<div class="" title="54976">54976</div>'
);
});
it('has checkboxes when selectRows is true or "checkbox"', function () {
let checkboxes = getTable(this.dom).querySelectorAll('.slds-checkbox');
checkboxes.should.have.length(7);
removeTable.call(this);
renderTable(
<DataTable {...defaultProps} selectRows={false}>
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
</DataTable>
).call(this);
checkboxes = getTable(this.dom).querySelectorAll('.slds-checkbox');
checkboxes.should.have.length(0);
removeTable.call(this);
renderTable(
<DataTable {...defaultProps} selectRows="checkbox">
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
</DataTable>
).call(this);
checkboxes = getTable(this.dom).querySelectorAll('.slds-checkbox');
checkboxes.should.have.length(7);
});
it('has radios only when selectRows is "radio"', function () {
const checkboxes = getTable(this.dom).querySelectorAll('.slds-checkbox');
checkboxes.should.have.length(7);
removeTable.call(this);
renderTable(
<DataTable {...defaultProps} selectRows="radio">
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
</DataTable>
).call(this);
const radios = getTable(this.dom).querySelectorAll('.slds-radio');
radios.should.have.length(6);
});
});
describe('Selectable - Checkbox', function describeFunction2() {
const defaultSelection = [
{
id: '8IKZHZZV80',
name: 'Cloudhub',
count: 100976,
lastModified: 'Yesterday',
},
];
afterEach(removeTable);
it('can start with a row selected', function () {
renderTable(
<DataTable {...defaultProps} selection={defaultSelection}>
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
</DataTable>
).call(this);
const tbody = getTable(this.dom).querySelectorAll('tbody')[0];
const selectedRows = tbody.querySelectorAll('tr.slds-is-selected');
selectedRows.should.have.length(1);
const checkedBoxes = tbody.querySelectorAll(
'.slds-checkbox input:checked'
);
checkedBoxes.should.have.length(1);
});
it('can start with a row disabled', function () {
const onChangeHandler = sinon.spy();
renderTable(
<DataTable
{...defaultProps}
selection={[]}
disabledSelection={defaultSelection}
onRowChange={onChangeHandler}
>
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
</DataTable>
).call(this);
const tbody = getTable(this.dom).querySelectorAll('tbody')[0];
const disabledRows = tbody.querySelectorAll(
'.slds-checkbox input:disabled'
);
disabledRows.should.have.length(1);
const checkbox = disabledRows[0];
Simulate.change(checkbox, { target: { checked: true } });
expect(onChangeHandler.callCount).to.equal(0);
});
it('can deselect a row', function (done) {
this.onRowChange = (event, { selection }) => {
selection.should.have.length(0);
done();
};
renderTable(
<DataTable
{...defaultProps}
selection={defaultSelection}
onRowChange={this.onRowChange}
>
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
</DataTable>
).call(this);
const tbody = getTable(this.dom).querySelectorAll('tbody')[0];
const selectedRow = tbody.querySelectorAll('tr.slds-is-selected')[0];
const checkbox = selectedRow.querySelectorAll('.slds-checkbox input')[0];
Simulate.change(checkbox, { target: { checked: false } });
});
it('can select a row', function (done) {
this.onRowChange = (event, { selection }) => {
selection.should.have.length(2);
selection[1].id.should.equal('5GJOOOPWU7');
done();
};
renderTable(
<DataTable
{...defaultProps}
selection={defaultSelection}
onRowChange={this.onRowChange}
>
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
</DataTable>
).call(this);
const secondRow = getRow(this.dom, 2);
const checkbox = secondRow.querySelectorAll('.slds-checkbox input')[0];
Simulate.change(checkbox, { target: { checked: true } });
});
it('can select all rows', function (done) {
this.onRowChange = (event, { selection }) => {
selection.should.have.length(6);
done();
};
renderTable(
<DataTable {...defaultProps} onRowChange={this.onRowChange}>
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
</DataTable>
).call(this);
const thead = getTable(this.dom).querySelectorAll('thead')[0];
const checkAll = thead.querySelectorAll('.slds-checkbox input')[0];
Simulate.change(checkAll, { target: { checked: true } });
});
it('can select all rows excluding disabled rows', function (done) {
this.onRowChange = (event, { selection }) => {
selection.should.have.length(5);
done();
};
renderTable(
<DataTable
{...defaultProps}
selection={[items[0]]}
disabledSelection={[items[0], items[1]]}
onRowChange={this.onRowChange}
>
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
</DataTable>
).call(this);
const thead = getTable(this.dom).querySelectorAll('thead')[0];
const checkAll = thead.querySelectorAll('.slds-checkbox input')[0];
Simulate.change(checkAll, { target: { checked: true } });
});
it('can deselect all rows', function (done) {
this.onRowChange = (event, { selection }) => {
selection.should.have.length(0);
done();
};
renderTable(
<DataTable
{...defaultProps}
selection={items}
onRowChange={this.onRowChange}
>
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
</DataTable>
).call(this);
const thead = getTable(this.dom).querySelectorAll('thead')[0];
const checkAll = thead.querySelectorAll('.slds-checkbox input')[0];
Simulate.change(checkAll, { target: { checked: false } });
});
it('can deselect all rows excluding disabled rows', function (done) {
this.onRowChange = (event, { selection }) => {
selection.should.have.length(2);
done();
};
renderTable(
<DataTable
{...defaultProps}
selection={items}
disabledSelection={[items[0], items[1]]}
onRowChange={this.onRowChange}
>
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
</DataTable>
).call(this);
const thead = getTable(this.dom).querySelectorAll('thead')[0];
const checkAll = thead.querySelectorAll('.slds-checkbox input')[0];
Simulate.change(checkAll, { target: { checked: false } });
});
it('can select all rows with header-rows present', function (done) {
this.onRowChange = (event, { selection }) => {
selection.should.have.length(6);
done();
};
renderTable(
<DataTable
{...defaultPropsWithHeaderRows}
onRowChange={this.onRowChange}
>
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
</DataTable>
).call(this);
const thead = getTable(this.dom).querySelectorAll('thead')[0];
const checkAll = thead.querySelectorAll('.slds-checkbox input')[0];
Simulate.change(checkAll, { target: { checked: true } });
});
it('can deselect all rows with header-rows present', function (done) {
this.onRowChange = (event, { selection }) => {
selection.should.have.length(0);
done();
};
renderTable(
<DataTable
{...defaultPropsWithHeaderRows}
selection={items}
onRowChange={this.onRowChange}
>
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
</DataTable>
).call(this);
const thead = getTable(this.dom).querySelectorAll('thead')[0];
const checkAll = thead.querySelectorAll('.slds-checkbox input')[0];
Simulate.change(checkAll, { target: { checked: false } });
});
});
describe('Selectable - Radio', function describeFunction2() {
const defaultSelection = [
{
id: '8IKZHZZV80',
name: 'Cloudhub',
count: 100976,
lastModified: 'Yesterday',
},
];
afterEach(removeTable);
it('can start with a row selected', function () {
renderTable(
<DataTable
{...defaultProps}
selection={defaultSelection}
selectRows="radio"
>
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
</DataTable>
).call(this);
const tbody = getTable(this.dom).querySelectorAll('tbody')[0];
const selectedRows = tbody.querySelectorAll('tr.slds-is-selected');
selectedRows.should.have.length(1);
const radios = tbody.querySelectorAll('.slds-radio input:checked');
radios.should.have.length(1);
});
it('can start with a row disabled', function () {
const onChangeHandler = sinon.spy();
renderTable(
<DataTable
{...defaultProps}
selection={[]}
disabledSelection={defaultSelection}
onRowChange={onChangeHandler}
selectRows="radio"
>
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
</DataTable>
).call(this);
const tbody = getTable(this.dom).querySelectorAll('tbody')[0];
const radios = tbody.querySelectorAll('.slds-radio input:disabled');
radios.should.have.length(1);
Simulate.change(radios[0], { target: { checked: true } });
expect(onChangeHandler.callCount).to.equal(0);
});
it('can select a row', function (done) {
this.onRowChange = (event, { selection }) => {
selection.should.have.length(1);
selection[0].id.should.equal('5GJOOOPWU7');
done();
};
renderTable(
<DataTable
{...defaultProps}
selection={defaultSelection}
selectRows="radio"
onRowChange={this.onRowChange}
>
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
</DataTable>
).call(this);
const secondRow = getRow(this.dom, 2);
const radio = secondRow.querySelectorAll('.slds-radio input')[0];
Simulate.change(radio, { target: { checked: true } });
});
});
describe('Sortable', function describeFunction2() {
afterEach(removeTable);
it('first clicked on sortable column header should result in ascending sort by default', function (done) {
this.onSort = (data) => {
data.property.should.equal('count');
data.sortDirection.should.equal('asc');
done();
};
renderTable(
<DataTable {...defaultProps} fixedLayout onSort={this.onSort}>
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
</DataTable>
).call(this);
const thead = getTable(this.dom).querySelectorAll('thead')[0];
const sortButton = thead.querySelectorAll('a')[0];
Simulate.click(sortButton, {});
});
it('if isDefaultSortDescending is true, first click on sortable column header should result in descending order', function (done) {
this.onSort = (data) => {
data.property.should.equal('count');
data.sortDirection.should.equal('desc');
done();
};
renderTable(
<DataTable {...defaultProps} fixedLayout onSort={this.onSort}>
{columns.map((columnProps) => (
<DataTableColumn
{...columnProps}
isDefaultSortDescending
key={columnProps.property}
/>
))}
</DataTable>
).call(this);
const thead = getTable(this.dom).querySelectorAll('thead')[0];
const sortButton = thead.querySelectorAll('a')[0];
Simulate.click(sortButton, {});
});
it('does not call onSort when a non-sortable column is clicked', function (done) {
this.onSort = () => {
done('sort called');
};
renderTable(
<DataTable {...defaultProps} onSort={this.onSort}>
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
</DataTable>
).call(this);
const thead = getTable(this.dom).querySelectorAll('thead')[0];
const secondColumn = thead.querySelectorAll('th')[1];
Simulate.click(secondColumn, {});
setTimeout(done, 0);
});
});
describe('w/ RowActions', function describeFunction2() {
afterEach(removeTable);
it('renders the RowActions and uses dropdown override property', function () {
renderTable(
<DataTable {...defaultProps}>
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
<DataTableRowActions
dropdown={
<Dropdown
options={[
{
id: 0,
label: 'Add to Group',
value: '1',
},
{
id: 1,
label: 'Publish',
value: '2',
},
]}
/>
}
/>
</DataTable>
).call(this);
const rowActionMenus = [
...this.component.getElementsByTagName('button'),
].filter((button) => button.textContent === 'Actions');
rowActionMenus.should.have.length(6);
});
it('calls onAction & onSelect when an action is clicked', function (done) {
let expectedCalbacks = 2;
this.onAction = (item, action) => {
item.id.should.equal('8IKZHZZV80');
action.value.should.equal('1');
// eslint-disable-next-line no-plusplus
if (!--expectedCalbacks) done();
};
this.onSelect = (action) => {
action.value.should.equal('1');
// eslint-disable-next-line no-plusplus
if (!--expectedCalbacks) done();
};
renderTable(
<DataTable {...defaultProps}>
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
<DataTableRowActions
onAction={this.onAction}
options={[
{
id: 0,
label: 'Add to Group',
value: '1',
},
{
id: 1,
label: 'Publish',
value: '2',
},
]}
dropdown={<Dropdown onSelect={this.onSelect} />}
/>
</DataTable>
).call(this);
const trigger = [...this.component.getElementsByTagName('button')].filter(
(button) => button.textContent === 'Actions'
)[0];
Simulate.click(trigger, {});
setTimeout(() => {
const menu = getMenu(document.body);
const firstAction = menu.querySelectorAll('.slds-dropdown__item')[0];
Simulate.click(firstAction.querySelector('a'), {});
}, 0);
});
});
describe('w/ HighlightCell', function describeFunction2() {
afterEach(removeTable);
it('marks the appropriate text in a cell', function () {
renderTable(
<DataTable {...defaultProps} search="Cloud">
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property}>
<DataTableHighlightCell />
</DataTableColumn>
))}
</DataTable>
).call(this);
const secondRow = getRow(this.dom, 2);
const markedText = secondRow.querySelectorAll('mark')[0];
markedText.innerHTML.should.equal('Cloud');
});
});
describe('w/ Fixed Headers', function describeFunction2() {
afterEach(removeTable);
it('Renders a fixedHeader table as expected', function () {
renderTable(
<DataTable
{...defaultProps}
fixedHeader
fixedLayout
id="DataTable-FixedHeader-Test"
onFixedHeaderResize={(event, data) => {
expect(Array.isArray(data.headerRefs)).to.eql(true);
expect(data.headerRefs.length).to.eql(4);
data.headerRefs.forEach((ref) => {
expect(typeof ref).to.eql('object');
});
expect(typeof data.scrollerRef).to.eql('object');
expect(
data.scrollerRef.className.search(
'slds-table_header-fixed_scroller'
) >= 0
).to.eql(true);
}}
onToggleFixedHeaderListeners={(event, data) => {
expect(typeof data.attach).to.eql('boolean');
expect(typeof data.resizeHandler).to.eql('function');
expect(typeof data.scrollerRef).to.eql('object');
expect(
data.scrollerRef.className.search(
'slds-table_header-fixed_scroller'
) >= 0
).to.eql(true);
}}
selectRows="checkbox"
>
<DataTableColumn
isSorted
label="Name"
primaryColumn
property="name"
sortable
sortDirection="asc"
/>
<DataTableColumn label="Count" property="count" />
<DataTableRowActions
options={[
{
id: 0,
label: 'Add to Group',
value: '1',
},
{
id: 1,
label: 'Publish',
value: '2',
},
]}
onAction={() => {}}
dropdown={<Dropdown length="5" />}
/>
</DataTable>
).call(this);
expect(
this.dom.querySelectorAll('.slds-table_header-fixed_container').length
).to.eql(1);
expect(
this.dom.querySelectorAll('.slds-table_header-fixed_scroller').length
).to.eql(1);
expect(
this.dom
.querySelector('table.slds-table')
.className.search('slds-table_header-fixed') >= 0
).to.eql(true);
expect(this.dom.querySelectorAll('thead .slds-cell-fixed').length).to.eql(
4
);
});
it('Renders a fixedHeader table with column resizing functionality as expected', function () {
renderTable(
<DataTable
{...defaultProps}
fixedHeader
fixedLayout
resizable
id="DataTable-resizable-cols-Test"
>
<DataTableColumn
isSorted
label="Name"
primaryColumn
property="name"
sortable
sortDirection="asc"
/>
<DataTableColumn label="Count" property="count" />
<DataTableRowActions
options={[
{
id: 0,
label: 'Add to Group',
value: '1',
},
{
id: 1,
label: 'Publish',
value: '2',
},
]}
onAction={() => {}}
dropdown={<Dropdown length="5" />}
/>
</DataTable>
).call(this);
// actions column is not resizable
expect(this.dom.querySelectorAll('.grip-resizable').length).to.eql(4);
expect(this.dom.querySelectorAll('.grip-container').length).to.eql(1);
});
});
describe('Column resizing', function describeFunction2() {
beforeEach(
mountComponent(
<DataTable
{...defaultProps}
fixedLayout
keyboardNavigation
resizable
resizableOptions={{
resizeMode: 'overflow',
onResize: () => {},
}}
>
{[
...columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
)),
...[
<DataTableRowActions
key="actions"
options={[
{
id: 0,
label: 'Add to Group',
value: '1',
},
{
id: 1,
label: 'Publish',
value: '2',
},
]}
onAction={() => {}}
dropdown={<Dropdown length="5" />}
/>,
],
]}
</DataTable>
)
);
afterEach(unmountComponent);
it('Resize functionality should work with left key', function () {
const initial = this.dom.querySelectorAll('th')[0].style.width;
let cell = this.wrapper.find('td').first();
cell.simulate('focus');
expect(this.wrapper.find('td').first().prop('tabIndex')).to.equal('0');
cell.simulate('keyDown', keyObjects.UP);
cell = this.wrapper.find('th').at(0);
expect(this.wrapper.find('th').first().prop('tabIndex')).to.equal('0');
cell.simulate('keyDown', keyObjects.ENTER);
cell.simulate('keyDown', keyObjects.LEFT);
cell.simulate('keyDown', keyObjects.LEFT);
cell.simulate('keyDown', keyObjects.LEFT);
cell.simulate('keyDown', keyObjects.ESCAPE);
expect(`${parseInt(initial, 10) - 30}px`).to.equal(
this.dom.querySelectorAll('th')[0].style.width
);
});
it('Resize functionality should work with right key', function () {
const initial = this.dom.querySelectorAll('th')[0].style.width;
let cell = this.wrapper.find('td').first();
cell.simulate('focus');
expect(this.wrapper.find('td').first().prop('tabIndex')).to.equal('0');
cell.simulate('keyDown', keyObjects.UP);
cell = this.wrapper.find('th').at(0);
expect(this.wrapper.find('th').first().prop('tabIndex')).to.equal('0');
cell.simulate('keyDown', keyObjects.ENTER);
cell.simulate('keyDown', keyObjects.RIGHT);
cell.simulate('keyDown', keyObjects.RIGHT);
cell.simulate('keyDown', keyObjects.RIGHT);
cell.simulate('keyDown', keyObjects.RIGHT);
cell.simulate('keyDown', keyObjects.RIGHT);
cell.simulate('keyDown', keyObjects.RIGHT);
cell.simulate('keyDown', keyObjects.ESCAPE);
expect(`${parseInt(initial, 10) + 60}px`).to.equal(
this.dom.querySelectorAll('th')[0].style.width
);
});
});
describe('w/ Infinite Scrolling', function describeFunction2() {
afterEach(removeTable);
it('renders a spinner as expected', function () {
renderTable(
<DataTable {...defaultProps} fixedHeader fixedLayout hasMore>
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
</DataTable>
).call(this);
expect(this.dom.querySelectorAll('.slds-spinner').length).to.eql(1);
});
it('onLoadMore callback is called when scroller is scrolled', function (done) {
let expectedCalbacks = 1;
this.onLoadMore = () => {
// eslint-disable-next-line no-plusplus
if (!--expectedCalbacks) done();
};
renderTable(
<DataTable
{...defaultProps}
fixedHeader
fixedLayout
hasMore
onLoadMore={this.onLoadMore}
>
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
</DataTable>
).call(this);
const scroller = this.dom.querySelector(
'.slds-table_header-fixed_scroller'
);
scroller.dispatchEvent(new Event('scroll'));
});
it('onLoadMore callback is called when window is resized', function (done) {
let expectedCalbacks = 1;
this.onLoadMore = () => {
// eslint-disable-next-line no-plusplus
if (!--expectedCalbacks) done();
};
renderTable(
<DataTable
{...defaultProps}
fixedHeader
fixedLayout
hasMore
onLoadMore={this.onLoadMore}
>
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
</DataTable>
).call(this);
window.dispatchEvent(new Event('resize'));
});
it('onLoadMore callback is called when the component is updated', function (done) {
let expectedCallbacks = 1;
this.onLoadMore = () => {
// eslint-disable-next-line no-plusplus
if (!--expectedCallbacks) done();
};
mountComponent(
<DataTable
{...defaultProps}
items={[]}
fixedHeader
fixedLayout
hasMore
onLoadMore={this.onLoadMore}
>
{columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
))}
</DataTable>
).call(this);
// Simulate the first page loading
this.wrapper.setProps({
items: [items[0]],
});
});
});
describe('Keyboard Navigation', function describeFunction2() {
beforeEach(
mountComponent(
<DataTable {...defaultProps} fixedLayout keyboardNavigation>
{[
...columns.map((columnProps) => (
<DataTableColumn {...columnProps} key={columnProps.property} />
)),
...[
<DataTableRowActions
key="actions"
options={[
{
id: 0,
label: 'Add to Group',
value: '1',
},
{
id: 1,
label: 'Publish',
value: '2',
},
]}
onAction={() => {}}
dropdown={<Dropdown length="5" />}
/>,
],
]}
</DataTable>
)
);
afterEach(unmountComponent);
it('moves selection when using keyboard up/down/left/right keys', function () {
// Focus the first cell
let cell = this.wrapper.find('td').first();
cell.simulate('focus');
expect(this.wrapper.find('td').first().prop('tabIndex')).to.equal('0');
// Press Right
cell.simulate('keyDown', keyObjects.RIGHT);
cell = this.wrapper.find('td').at(1);
expect(cell.prop('tabIndex')).to.equal('0');
// Press Down
cell.simulate('keyDown', keyObjects.DOWN);
cell = this.wrapper.find('td').at(5);
expect(cell.prop('tabIndex')).to.equal('0');
// Press Left
cell.simulate('keyDown', keyObjects.LEFT);
cell = this.wrapper.find('td').at(4);
expect(cell.prop('tabIndex')).to.equal('0');
// Press Up
cell.simulate('keyDown', keyObjects.UP);
cell = this.wrapper.find('td').at(0);
expect(cell.prop('tabIndex')).to.equal('0');
});
it('enters actionable mode when using keyboard enter key; and enters navigation mode when using keyboard escape key', function () {
// Focus the first cell
let cell = this.wrapper.find('td').first();
cell.simulate('focus');
expect(this.wrapper.find('td').first().prop('tabIndex')).to.equal('0');
// Press Enter
cell.simulate('keyDown', keyObjects.ENTER);
cell = this.wrapper.find('td').first();
expect(cell.prop('tabIndex')).to.be.undefined;
let checkbox = this.wrapper
.find('td')
.first()
.find('input[type="checkbox"]');
expect(checkbox.prop('tabIndex')).to.equal('0');
// Press Escape
cell.simulate('keyDown', keyObjects.ESCAPE);
cell = this.wrapper.find('td').first();
expect(cell.prop('tabIndex')).to.equal('0');
checkbox = this.wrapper.find('td').first().find('input[type="checkbox"]');
expect(checkbox.prop('tabIndex')).to.equal('-1');
// Navigate to Dropdown
cell.simulate('keyDown', keyObjects.RIGHT);
cell.simulate('keyDown', keyObjects.RIGHT);
cell.simulate('keyDown', keyObjects.RIGHT);
// Press Enter
cell.simulate('keyDown', keyObjects.ENTER);
let dropdownTrigger = this.wrapper
.find('td')
.at(3)
.find('.slds-dropdown-trigger button');
expect(dropdownTrigger.prop('tabIndex')).to.equal('0');
// Press Escape
cell.simulate('keyDown', keyObjects.ESCAPE);
dropdownTrigger = this.wrapper
.find('td')
.at(3)
.find('.slds-dropdown-trigger button');
expect(dropdownTrigger.prop('tabIndex')).to.equal('-1');
});
});
});