mirror of
https://github.com/gosticks/react-bootstrap-table2.git
synced 2025-10-16 11:55:39 +00:00
fix #47
* implement table sort * path for component test for table sort * add store/base test * add store/sort test * add story for sort * add column.sort and column.sortFunc
This commit is contained in:
parent
ec1a927001
commit
2e10cb132e
@ -10,13 +10,15 @@ Available properties in a column object:
|
||||
* [hidden](#hidden)
|
||||
* [formatter](#formatter)
|
||||
* [formatExtraData](#formatExtraData)
|
||||
* [headerFormatter](#headerFormatter)
|
||||
* [sort](#sort)
|
||||
* [sortFunc](#sortFunc)
|
||||
* [classes](#classes)
|
||||
* [style](#style)
|
||||
* [title](#title)
|
||||
* [events](#events)
|
||||
* [align](#align)
|
||||
* [attrs](#attrs)
|
||||
* [headerFormatter](#headerFormatter)
|
||||
* [headerClasses](#headerClasses)
|
||||
* [headerStyle](#headerStyle)
|
||||
* [headerTitle](#headerTitle)
|
||||
@ -85,6 +87,24 @@ dataField: 'address.city'
|
||||
## <a name='formatExtraData'>column.formatExtraData - [Any]</a>
|
||||
It's only used for [`column.formatter`](#formatter), you can define any value for it and will be passed as fourth argument for [`column.formatter`](#formatter) callback function.
|
||||
|
||||
## <a name='sort'>column.sort - [Bool]</a>
|
||||
Enable the column sort via a `true` value given.
|
||||
|
||||
## <a name='sortFunc'>column.sortFunc - [Function]</a>
|
||||
`column.sortFunc` only work when `column.sort` is enable. `sortFunc` allow you to define your sorting algorithm. This callback function accept four arguments:
|
||||
|
||||
```js
|
||||
{
|
||||
// omit...
|
||||
sort: true,
|
||||
sortFunc: (a, b, order, dataField) => {
|
||||
if (order === 'asc') return a - b;
|
||||
else return b - a;
|
||||
}
|
||||
}
|
||||
```
|
||||
> The possible value of `order` argument is **`asc`** and **`desc`**.
|
||||
|
||||
## <a name='classes'>column.classes - [String | Function]</a>
|
||||
It's availabe to have custom class on table column:
|
||||
|
||||
|
||||
60
packages/react-bootstrap-table2-example/examples/sort/custom-sort-table.js
vendored
Normal file
60
packages/react-bootstrap-table2-example/examples/sort/custom-sort-table.js
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
/* eslint no-unused-vars: 0 */
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { BootstrapTableful } from 'react-bootstrap-table2';
|
||||
import Code from 'components/common/code-block';
|
||||
import { productsGenerator } from 'utils/common';
|
||||
|
||||
const products = productsGenerator();
|
||||
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID',
|
||||
sort: true,
|
||||
// here, we implement a custom sort which perform a reverse sorting
|
||||
sortFunc: (a, b, order, dataField) => {
|
||||
if (order === 'asc') {
|
||||
return b - a;
|
||||
}
|
||||
return a - b; // desc
|
||||
}
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name',
|
||||
sort: true
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price'
|
||||
}];
|
||||
|
||||
const sourceCode = `\
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID',
|
||||
sort: true,
|
||||
// here, we implement a custom sort which perform a reverse sorting
|
||||
sortFunc: (a, b, order, dataField) => {
|
||||
if (order === 'asc') {
|
||||
return b - a;
|
||||
}
|
||||
return a - b; // desc
|
||||
}
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name',
|
||||
sort: true
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price'
|
||||
}];
|
||||
|
||||
<BootstrapTableful keyField='id' data={ products } columns={ columns } />
|
||||
`;
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<BootstrapTableful keyField="id" data={ products } columns={ columns } />
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
44
packages/react-bootstrap-table2-example/examples/sort/enable-sort-table.js
vendored
Normal file
44
packages/react-bootstrap-table2-example/examples/sort/enable-sort-table.js
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
import React from 'react';
|
||||
|
||||
import { BootstrapTableful } from 'react-bootstrap-table2';
|
||||
import Code from 'components/common/code-block';
|
||||
import { productsGenerator } from 'utils/common';
|
||||
|
||||
const products = productsGenerator();
|
||||
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID',
|
||||
sort: true
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name',
|
||||
sort: true
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price'
|
||||
}];
|
||||
|
||||
const sourceCode = `\
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID',
|
||||
sort: true
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name',
|
||||
sort: true
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price'
|
||||
}];
|
||||
|
||||
<BootstrapTableful keyField='id' data={ products } columns={ columns } />
|
||||
`;
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<BootstrapTableful keyField="id" data={ products } columns={ columns } />
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
@ -31,6 +31,10 @@ import HeaderColumnClassTable from 'examples/header-columns/column-class-table';
|
||||
import HeaderColumnStyleTable from 'examples/header-columns/column-style-table';
|
||||
import HeaderColumnAttrsTable from 'examples/header-columns/column-attrs-table';
|
||||
|
||||
// table sort
|
||||
import EnableSortTable from 'examples/sort/enable-sort-table';
|
||||
import CustomSortTable from 'examples/sort/custom-sort-table';
|
||||
|
||||
// css style
|
||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
import 'stories/stylesheet/tomorrow.min.css';
|
||||
@ -69,3 +73,7 @@ storiesOf('Work on Header Columns', module)
|
||||
.add('Customize Column Class', () => <HeaderColumnClassTable />)
|
||||
.add('Customize Column Style', () => <HeaderColumnStyleTable />)
|
||||
.add('Customize Column HTML attribute', () => <HeaderColumnAttrsTable />);
|
||||
|
||||
storiesOf('Sort Table', module)
|
||||
.add('Enable Sort', () => <EnableSortTable />)
|
||||
.add('Custom Sort Fuction', () => <CustomSortTable />);
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
/* eslint arrow-body-style: 0 */
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import cs from 'classnames';
|
||||
@ -13,11 +14,15 @@ class BootstrapTable extends PropsBaseResolver(Component) {
|
||||
this.validateProps();
|
||||
const { store } = this.props;
|
||||
this.store = !store ? new Store(props) : store;
|
||||
|
||||
this.handleSort = this.handleSort.bind(this);
|
||||
this.state = {
|
||||
data: this.store.get()
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
data,
|
||||
columns,
|
||||
keyField,
|
||||
striped,
|
||||
@ -37,9 +42,14 @@ class BootstrapTable extends PropsBaseResolver(Component) {
|
||||
return (
|
||||
<div className="react-bootstrap-table-container">
|
||||
<table className={ tableClass }>
|
||||
<Header columns={ columns } />
|
||||
<Header
|
||||
columns={ columns }
|
||||
sortField={ this.store.sortField }
|
||||
sortOrder={ this.store.sortOrder }
|
||||
onSort={ this.handleSort }
|
||||
/>
|
||||
<Body
|
||||
data={ data }
|
||||
data={ this.state.data }
|
||||
keyField={ keyField }
|
||||
columns={ columns }
|
||||
isEmpty={ this.isEmpty() }
|
||||
@ -50,6 +60,16 @@ class BootstrapTable extends PropsBaseResolver(Component) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
handleSort(column) {
|
||||
this.store.sortBy(column);
|
||||
|
||||
this.setState(() => {
|
||||
return {
|
||||
data: this.store.get()
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
BootstrapTable.propTypes = {
|
||||
|
||||
4
packages/react-bootstrap-table2/src/const.js
vendored
Normal file
4
packages/react-bootstrap-table2/src/const.js
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
export default {
|
||||
SORT_ASC: 'asc',
|
||||
SORT_DESC: 'desc'
|
||||
};
|
||||
@ -1,12 +1,25 @@
|
||||
/* eslint react/require-default-props: 0 */
|
||||
import React from 'react';
|
||||
import cs from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import Const from './const';
|
||||
import SortSymbol from './sort-symbol';
|
||||
import SortCaret from './sort-caret';
|
||||
import _ from './utils';
|
||||
|
||||
|
||||
const HeaderCell = ({ column, index }) => {
|
||||
const HeaderCell = (props) => {
|
||||
const {
|
||||
column,
|
||||
index,
|
||||
onSort,
|
||||
sorting,
|
||||
sortOrder
|
||||
} = props;
|
||||
const {
|
||||
text,
|
||||
sort,
|
||||
hidden,
|
||||
headerTitle,
|
||||
headerAlign,
|
||||
@ -25,6 +38,7 @@ const HeaderCell = ({ column, index }) => {
|
||||
const cellClasses = _.isFunction(headerClasses) ? headerClasses(column, index) : headerClasses;
|
||||
|
||||
let cellStyle = {};
|
||||
let sortSymbol;
|
||||
|
||||
if (headerStyle) {
|
||||
cellStyle = _.isFunction(headerStyle) ? headerStyle(column, index) : headerStyle;
|
||||
@ -46,9 +60,24 @@ const HeaderCell = ({ column, index }) => {
|
||||
|
||||
if (!_.isEmptyObject(cellStyle)) cellAttrs.style = cellStyle;
|
||||
|
||||
if (sort) {
|
||||
const customClick = cellAttrs.onClick;
|
||||
cellAttrs.onClick = (e) => {
|
||||
onSort(column);
|
||||
if (_.isFunction(customClick)) customClick(e);
|
||||
};
|
||||
cellAttrs.className = cs(cellAttrs.className, 'sortable');
|
||||
|
||||
if (sorting) {
|
||||
sortSymbol = <SortCaret order={ sortOrder } />;
|
||||
} else {
|
||||
sortSymbol = <SortSymbol />;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<th { ...cellAttrs }>
|
||||
{ children }
|
||||
{ children }{ sortSymbol }
|
||||
</th>
|
||||
);
|
||||
};
|
||||
@ -68,9 +97,14 @@ HeaderCell.propTypes = {
|
||||
headerEvents: PropTypes.object,
|
||||
events: PropTypes.object,
|
||||
headerAlign: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||||
align: PropTypes.oneOfType([PropTypes.string, PropTypes.func])
|
||||
align: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||||
sort: PropTypes.bool,
|
||||
sortFunc: PropTypes.func
|
||||
}).isRequired,
|
||||
index: PropTypes.number.isRequired
|
||||
index: PropTypes.number.isRequired,
|
||||
onSort: PropTypes.func,
|
||||
sorting: PropTypes.bool,
|
||||
sortOrder: PropTypes.oneOf([Const.SORT_ASC, Const.SORT_DESC])
|
||||
};
|
||||
|
||||
export default HeaderCell;
|
||||
|
||||
44
packages/react-bootstrap-table2/src/header.js
vendored
44
packages/react-bootstrap-table2/src/header.js
vendored
@ -1,22 +1,44 @@
|
||||
/* eslint react/require-default-props: 0 */
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import HeaderCell from './header-cell';
|
||||
|
||||
|
||||
const Header = ({ columns }) => (
|
||||
<thead>
|
||||
<tr>
|
||||
{
|
||||
columns.map((column, i) =>
|
||||
<HeaderCell key={ column.dataField } column={ column } index={ i } />)
|
||||
}
|
||||
</tr>
|
||||
</thead>
|
||||
);
|
||||
const Header = (props) => {
|
||||
const {
|
||||
columns,
|
||||
onSort,
|
||||
sortField,
|
||||
sortOrder
|
||||
} = props;
|
||||
return (
|
||||
<thead>
|
||||
<tr>
|
||||
{
|
||||
columns.map((column, i) => {
|
||||
const currSort = column.dataField === sortField;
|
||||
return (
|
||||
<HeaderCell
|
||||
index={ i }
|
||||
key={ column.dataField }
|
||||
column={ column }
|
||||
onSort={ onSort }
|
||||
sorting={ currSort }
|
||||
sortOrder={ sortOrder }
|
||||
/>);
|
||||
})
|
||||
}
|
||||
</tr>
|
||||
</thead>
|
||||
);
|
||||
};
|
||||
|
||||
Header.propTypes = {
|
||||
columns: PropTypes.array.isRequired
|
||||
columns: PropTypes.array.isRequired,
|
||||
onSort: PropTypes.func,
|
||||
sortField: PropTypes.string,
|
||||
sortOrder: PropTypes.string
|
||||
};
|
||||
|
||||
export default Header;
|
||||
|
||||
21
packages/react-bootstrap-table2/src/sort-caret.js
vendored
Normal file
21
packages/react-bootstrap-table2/src/sort-caret.js
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
import React from 'react';
|
||||
import cs from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import Const from './const';
|
||||
|
||||
const SortCaret = ({ order }) => {
|
||||
const orderClass = cs('react-bootstrap-table-sort-order', {
|
||||
dropup: order === Const.SORT_ASC
|
||||
});
|
||||
return (
|
||||
<span className={ orderClass }>
|
||||
<span className="caret" />
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
SortCaret.propTypes = {
|
||||
order: PropTypes.oneOf([Const.SORT_ASC, Const.SORT_DESC]).isRequired
|
||||
};
|
||||
export default SortCaret;
|
||||
13
packages/react-bootstrap-table2/src/sort-symbol.js
vendored
Normal file
13
packages/react-bootstrap-table2/src/sort-symbol.js
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
import React from 'react';
|
||||
|
||||
const SortSymbol = () => (
|
||||
<span className="order">
|
||||
<span className="dropdown">
|
||||
<span className="caret" />
|
||||
</span>
|
||||
<span className="dropup">
|
||||
<span className="caret" />
|
||||
</span>
|
||||
</span>);
|
||||
|
||||
export default SortSymbol;
|
||||
@ -1,10 +1,31 @@
|
||||
import { sort } from './sort';
|
||||
import Const from '../const';
|
||||
|
||||
export default class Store {
|
||||
constructor(props) {
|
||||
const { data } = props;
|
||||
this.data = data ? data.slice() : [];
|
||||
|
||||
this.sortOrder = undefined;
|
||||
this.sortField = undefined;
|
||||
}
|
||||
|
||||
isEmpty() {
|
||||
return this.data.length === 0;
|
||||
}
|
||||
|
||||
sortBy({ dataField, sortFunc }) {
|
||||
if (dataField !== this.sortField) {
|
||||
this.sortOrder = Const.SORT_DESC;
|
||||
} else {
|
||||
this.sortOrder = this.sortOrder === Const.SORT_DESC ? Const.SORT_ASC : Const.SORT_DESC;
|
||||
}
|
||||
|
||||
this.data = sort(dataField, this.data, this.sortOrder, sortFunc);
|
||||
this.sortField = dataField;
|
||||
}
|
||||
|
||||
get() {
|
||||
return this.data;
|
||||
}
|
||||
}
|
||||
|
||||
40
packages/react-bootstrap-table2/src/store/sort.js
vendored
Normal file
40
packages/react-bootstrap-table2/src/store/sort.js
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
/* eslint no-nested-ternary: 0 */
|
||||
/* eslint no-lonely-if: 0 */
|
||||
/* eslint no-underscore-dangle: 0 */
|
||||
import _ from '../utils';
|
||||
import Const from '../const';
|
||||
|
||||
function comparator(a, b) {
|
||||
let result;
|
||||
if (typeof b === 'string') {
|
||||
result = b.localeCompare(a);
|
||||
} else {
|
||||
result = a > b ? -1 : ((a < b) ? 1 : 0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const sort = (dataField, data, order, sortFunc) => {
|
||||
const _data = [...data];
|
||||
_data.sort((a, b) => {
|
||||
let result;
|
||||
let valueA = _.get(a, dataField);
|
||||
let valueB = _.get(b, dataField);
|
||||
valueA = _.isDefined(valueA) ? valueA : '';
|
||||
valueB = _.isDefined(valueB) ? valueB : '';
|
||||
|
||||
if (sortFunc) {
|
||||
result = sortFunc(valueA, valueB, order, dataField);
|
||||
} else {
|
||||
if (order === Const.SORT_DESC) {
|
||||
result = comparator(valueA, valueB);
|
||||
} else {
|
||||
result = comparator(valueB, valueA);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
});
|
||||
return _data;
|
||||
};
|
||||
|
||||
export { sort };
|
||||
7
packages/react-bootstrap-table2/src/utils.js
vendored
7
packages/react-bootstrap-table2/src/utils.js
vendored
@ -40,9 +40,14 @@ function isEmptyObject(obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function isDefined(value) {
|
||||
return typeof value !== 'undefined' && value !== null;
|
||||
}
|
||||
|
||||
export default {
|
||||
get,
|
||||
isFunction,
|
||||
isObject,
|
||||
isEmptyObject
|
||||
isEmptyObject,
|
||||
isDefined
|
||||
};
|
||||
|
||||
@ -1,5 +1,24 @@
|
||||
.react-bootstrap-table-container {
|
||||
|
||||
th.sortable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
th > .order > .dropdown > .caret {
|
||||
margin: 10px 0 10px 5px;
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
th > .order > .dropup > .caret {
|
||||
margin: 10px 0;
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
th > .react-bootstrap-table-sort-order > .caret {
|
||||
margin: 10px 6.5px;
|
||||
}
|
||||
|
||||
td.react-bs-table-no-data {
|
||||
text-align: center
|
||||
}
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,9 @@ import React from 'react';
|
||||
import sinon from 'sinon';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import Const from '../src/const';
|
||||
import SortCaret from '../src/sort-caret';
|
||||
import SortSymbol from '../src/sort-symbol';
|
||||
import HeaderCell from '../src/header-cell';
|
||||
|
||||
describe('HeaderCell', () => {
|
||||
@ -385,4 +388,75 @@ describe('HeaderCell', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when column.sort is enable', () => {
|
||||
let column;
|
||||
let onSortCallBack;
|
||||
|
||||
beforeEach(() => {
|
||||
column = {
|
||||
dataField: 'id',
|
||||
text: 'ID',
|
||||
sort: true
|
||||
};
|
||||
onSortCallBack = sinon.stub().withArgs(column);
|
||||
wrapper = shallow(<HeaderCell column={ column } index={ index } onSort={ onSortCallBack } />);
|
||||
});
|
||||
|
||||
it('should have sortable class on header cell', () => {
|
||||
expect(wrapper.hasClass('sortable')).toBe(true);
|
||||
});
|
||||
|
||||
it('should have onClick event on header cell', () => {
|
||||
expect(wrapper.find('th').prop('onClick')).toBeDefined();
|
||||
});
|
||||
|
||||
it('should trigger onSort callback when click on header cell', () => {
|
||||
wrapper.find('th').simulate('click');
|
||||
expect(onSortCallBack.callCount).toBe(1);
|
||||
});
|
||||
|
||||
describe('and sorting prop is false', () => {
|
||||
it('header should render SortSymbol as default', () => {
|
||||
expect(wrapper.find(SortSymbol).length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('and sorting prop is true', () => {
|
||||
[Const.SORT_ASC, Const.SORT_DESC].forEach((order) => {
|
||||
describe(`and sortOrder is ${order}`, () => {
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(
|
||||
<HeaderCell column={ column } index={ index } sortOrder={ order } sorting />);
|
||||
});
|
||||
|
||||
it('should render SortCaret correctly', () => {
|
||||
expect(wrapper.find(SortCaret).length).toBe(1);
|
||||
expect(wrapper.find(SortCaret).prop('order')).toEqual(order);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when column.headerEvents prop is defined and have custom onClick', () => {
|
||||
beforeEach(() => {
|
||||
column = {
|
||||
dataField: 'id',
|
||||
text: 'ID',
|
||||
sort: true,
|
||||
headerEvents: {
|
||||
onClick: sinon.stub()
|
||||
}
|
||||
};
|
||||
wrapper = shallow(
|
||||
<HeaderCell column={ column } index={ index } onSort={ onSortCallBack } />);
|
||||
});
|
||||
|
||||
it('custom event hook should still be called when triggering sorting', () => {
|
||||
wrapper.find('th').simulate('click');
|
||||
expect(onSortCallBack.callCount).toBe(1);
|
||||
expect(column.headerEvents.onClick.callCount).toBe(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -3,6 +3,7 @@ import { shallow } from 'enzyme';
|
||||
|
||||
import HeaderCell from '../src/header-cell';
|
||||
import Header from '../src/header';
|
||||
import Const from '../src/const';
|
||||
|
||||
describe('Header', () => {
|
||||
let wrapper;
|
||||
@ -25,4 +26,21 @@ describe('Header', () => {
|
||||
expect(wrapper.find(HeaderCell).length).toBe(columns.length);
|
||||
});
|
||||
});
|
||||
|
||||
describe('header with columns enable sort', () => {
|
||||
const sortField = columns[1].dataField;
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(
|
||||
<Header columns={ columns } sortField={ sortField } sortOrder={ Const.SORT_ASC } />);
|
||||
});
|
||||
|
||||
it('The HeaderCell should receive correct sorting props', () => {
|
||||
const headerCells = wrapper.find(HeaderCell);
|
||||
expect(headerCells.length).toBe(columns.length);
|
||||
expect(headerCells.at(0).prop('sorting')).toBe(false);
|
||||
expect(headerCells.at(1).prop('sorting')).toBe(true);
|
||||
expect(headerCells.at(1).prop('sortOrder')).toBe(Const.SORT_ASC);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
37
packages/react-bootstrap-table2/test/sort-caret.test.js
Normal file
37
packages/react-bootstrap-table2/test/sort-caret.test.js
Normal file
@ -0,0 +1,37 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import Const from '../src/const';
|
||||
import SortCaret from '../src/sort-caret';
|
||||
|
||||
describe('SortCaret', () => {
|
||||
let wrapper;
|
||||
|
||||
describe(`when order prop is ${Const.SORT_ASC}`, () => {
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(
|
||||
<SortCaret order={ Const.SORT_ASC } />);
|
||||
});
|
||||
|
||||
it('should render caret correctly', () => {
|
||||
expect(wrapper.length).toBe(1);
|
||||
expect(wrapper.find('span').length).toBe(2);
|
||||
expect(wrapper.find('.caret').length).toBe(1);
|
||||
expect(wrapper.find('.dropup').length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe(`when order prop is ${Const.SORT_DESC}`, () => {
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(
|
||||
<SortCaret order={ Const.SORT_DESC } />);
|
||||
});
|
||||
|
||||
it('should render caret correctly', () => {
|
||||
expect(wrapper.length).toBe(1);
|
||||
expect(wrapper.find('span').length).toBe(2);
|
||||
expect(wrapper.find('.caret').length).toBe(1);
|
||||
expect(wrapper.find('.dropup').length).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
19
packages/react-bootstrap-table2/test/sort-symbol.test.js
Normal file
19
packages/react-bootstrap-table2/test/sort-symbol.test.js
Normal file
@ -0,0 +1,19 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import SortSymbol from '../src/sort-symbol';
|
||||
|
||||
describe('SortSymbol', () => {
|
||||
let wrapper;
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(
|
||||
<SortSymbol />);
|
||||
});
|
||||
it('should render sort symbol correctly', () => {
|
||||
expect(wrapper.length).toBe(1);
|
||||
expect(wrapper.find('.order').length).toBe(1);
|
||||
expect(wrapper.find('.caret').length).toBe(2);
|
||||
expect(wrapper.find('.dropdown').length).toBe(1);
|
||||
expect(wrapper.find('.dropup').length).toBe(1);
|
||||
});
|
||||
});
|
||||
75
packages/react-bootstrap-table2/test/store/base.test.js
Normal file
75
packages/react-bootstrap-table2/test/store/base.test.js
Normal file
@ -0,0 +1,75 @@
|
||||
import Base from '../../src/store/base';
|
||||
import Const from '../../src/const';
|
||||
|
||||
describe('Store Base', () => {
|
||||
let store;
|
||||
const data = [
|
||||
{ id: 3, name: 'name2' },
|
||||
{ id: 2, name: 'ABC' },
|
||||
{ id: 4, name: '123tester' },
|
||||
{ id: 1, name: '!@#' }
|
||||
];
|
||||
|
||||
beforeEach(() => {
|
||||
store = new Base({ data });
|
||||
});
|
||||
|
||||
describe('initialize', () => {
|
||||
it('should have correct initialize data', () => {
|
||||
expect(store.sortOrder).toBeUndefined();
|
||||
expect(store.sortField).toBeUndefined();
|
||||
expect(store.data.length).toEqual(data.length);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isEmpty', () => {
|
||||
beforeEach(() => {
|
||||
store = new Base({ data: [] });
|
||||
});
|
||||
|
||||
it('should have correct initialize data', () => {
|
||||
expect(store.isEmpty()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('sortBy', () => {
|
||||
let dataField;
|
||||
|
||||
beforeEach(() => {
|
||||
dataField = 'name';
|
||||
});
|
||||
|
||||
it('should change sortField by dataField param', () => {
|
||||
store.sortBy({ dataField });
|
||||
expect(store.sortField).toEqual(dataField);
|
||||
});
|
||||
|
||||
it('should change sortOrder correctly when sortBy same dataField', () => {
|
||||
store.sortBy({ dataField });
|
||||
expect(store.sortOrder).toEqual(Const.SORT_DESC);
|
||||
store.sortBy({ dataField });
|
||||
expect(store.sortOrder).toEqual(Const.SORT_ASC);
|
||||
});
|
||||
|
||||
it('should change sortOrder correctly when sortBy different dataField', () => {
|
||||
store.sortBy({ dataField });
|
||||
expect(store.sortOrder).toEqual(Const.SORT_DESC);
|
||||
|
||||
dataField = 'id';
|
||||
store.sortBy({ dataField });
|
||||
expect(store.sortOrder).toEqual(Const.SORT_DESC);
|
||||
|
||||
dataField = 'name';
|
||||
store.sortBy({ dataField });
|
||||
expect(store.sortOrder).toEqual(Const.SORT_DESC);
|
||||
});
|
||||
|
||||
it('should have correct result after sortBy', () => {
|
||||
store.sortBy({ dataField });
|
||||
const result = store.data.map(e => e[dataField]).sort((a, b) => b - a);
|
||||
store.get().forEach((e, i) => {
|
||||
expect(e[dataField]).toEqual(result[i]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
39
packages/react-bootstrap-table2/test/store/sort.test.js
Normal file
39
packages/react-bootstrap-table2/test/store/sort.test.js
Normal file
@ -0,0 +1,39 @@
|
||||
import sinon from 'sinon';
|
||||
|
||||
import { sort } from '../../src/store/sort';
|
||||
import Const from '../../src/const';
|
||||
|
||||
describe('Sort Function', () => {
|
||||
const data = [
|
||||
{ id: 3, name: 'name2' },
|
||||
{ id: 2, name: 'ABC' },
|
||||
{ id: 4, name: '123tester' },
|
||||
{ id: 1, name: '!@#' }
|
||||
];
|
||||
|
||||
it('should sort array with ASC order correctly', () => {
|
||||
const result = sort('id', data, Const.SORT_ASC);
|
||||
expect(result.length).toEqual(data.length);
|
||||
|
||||
const sortedArray = data.map(e => e.id).sort((a, b) => a - b);
|
||||
sortedArray.forEach((e, i) => {
|
||||
expect(e).toEqual(result[i].id);
|
||||
});
|
||||
});
|
||||
|
||||
it('should sort array with DESC order correctly', () => {
|
||||
const result = sort('id', data, Const.SORT_DESC);
|
||||
expect(result.length).toEqual(data.length);
|
||||
|
||||
const sortedArray = data.map(e => e.id).sort((a, b) => b - a);
|
||||
sortedArray.forEach((e, i) => {
|
||||
expect(e).toEqual(result[i].id);
|
||||
});
|
||||
});
|
||||
|
||||
it('should call custom sort function when sortFunc given', () => {
|
||||
const sortFunc = sinon.stub().returns(1);
|
||||
sort('id', data, Const.SORT_DESC, sortFunc);
|
||||
expect(sortFunc.callCount).toBe(6);
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user