Implement number filter
This commit is contained in:
Allen 2018-02-10 16:15:37 +08:00 committed by GitHub
commit 024bba15fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 994 additions and 7 deletions

View File

@ -85,7 +85,7 @@ Please see [available filter configuration](https://react-bootstrap-table.github
- [ ] Regex Filter
- [x] Select Filter
- [x] Custom Select Filter
- [ ] Number Filter
- [X] Number Filter
- [ ] Date Filter
- [ ] Array Filter
- [ ] Programmatically Filter

View File

@ -0,0 +1,74 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { numberFilter, Comparator } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(8);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price',
filter: numberFilter({
options: [2100, 2103, 2105],
delay: 600,
placeholder: 'custom placeholder',
withoutEmptyComparatorOption: true,
comparators: [Comparator.EQ, Comparator.GT, Comparator.LT],
style: { display: 'inline-grid' },
className: 'custom-numberfilter-class',
comparatorStyle: { backgroundColor: 'antiquewhite' },
comparatorClassName: 'custom-comparator-class',
numberStyle: { backgroundColor: 'cadetblue', margin: '0px' },
numberClassName: 'custom-number-class'
})
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { numberFilter, Comparator } from 'react-bootstrap-table2-filter';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price',
filter: numberFilter({
options: [2100, 2103, 2105],
delay: 600,
placeholder: 'custom placeholder',
withoutEmptyComparatorOption: true,
comparators: [Comparator.EQ, Comparator.GT, Comparator.LT],
style: { display: 'inline-grid' },
className: 'custom-numberfilter-class',
comparatorStyle: { backgroundColor: 'antiquewhite' },
comparatorClassName: 'custom-comparator-class',
numberStyle: { backgroundColor: 'cadetblue', margin: '0px' },
numberClassName: 'custom-number-class'
})
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
`;
export default () => (
<div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,54 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { numberFilter, Comparator } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(8);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price',
filter: numberFilter({
defaultValue: { number: 2103, comparator: Comparator.GT }
})
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { numberFilter, Comparator } from 'react-bootstrap-table2-filter';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price',
filter: numberFilter({
defaultValue: { number: 2103, comparator: Comparator.GT }
})
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
`;
export default () => (
<div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,50 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { numberFilter } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(8);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price',
filter: numberFilter()
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { numberFilter } from 'react-bootstrap-table2-filter';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price',
filter: numberFilter()
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
`;
export default () => (
<div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -43,6 +43,9 @@ import SelectFilter from 'examples/column-filter/select-filter';
import SelectFilterWithDefaultValue from 'examples/column-filter/select-filter-default-value';
import SelectFilterComparator from 'examples/column-filter/select-filter-like-comparator';
import CustomSelectFilter from 'examples/column-filter/custom-select-filter';
import NumberFilter from 'examples/column-filter/number-filter';
import NumberFilterWithDefaultValue from 'examples/column-filter/number-filter-default-value';
import CustomNumberFilter from 'examples/column-filter/custom-number-filter';
// work on rows
import RowStyleTable from 'examples/rows/row-style';
@ -143,12 +146,15 @@ storiesOf('Column Filter', module)
.add('Text Filter', () => <TextFilter />)
.add('Text Filter with Default Value', () => <TextFilterWithDefaultValue />)
.add('Text Filter with Comparator', () => <TextFilterComparator />)
.add('Custom Text Filter', () => <CustomTextFilter />)
// add another filter type example right here.
.add('Select Filter', () => <SelectFilter />)
.add('Select Filter with Default Value', () => <SelectFilterWithDefaultValue />)
.add('Select Filter with Comparator', () => <SelectFilterComparator />)
.add('Number Filter', () => <NumberFilter />)
.add('Number Filter with Default Value', () => <NumberFilterWithDefaultValue />)
.add('Custom Text Filter', () => <CustomTextFilter />)
.add('Custom Select Filter', () => <CustomSelectFilter />)
.add('Custom Number Filter', () => <CustomNumberFilter />)
.add('Custom Filter Value', () => <CustomFilterValue />);
storiesOf('Work on Rows', module)

View File

@ -18,6 +18,7 @@ You can get all types of filters via import and these filters are a factory func
* TextFilter
* SelectFilter
* NumberFilter
* **Coming soon!**
## Add CSS
@ -107,5 +108,44 @@ const qualityFilter = selectFilter({
withoutEmptyOption: true // hide the default select option
});
// omit...
```
## Number Filter
```js
import filterFactory, { numberFilter } from 'react-bootstrap-table2-filter';
const columns = [..., {
dataField: 'price',
text: 'Product Price',
filter: numberFilter()
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
```
Numner filter is same as other filter, you can custom the number filter via `numberFilter` factory function:
```js
import filterFactory, { selectFilter, Comparator } from 'react-bootstrap-table2-filter';
// omit...
const numberFilter = numberFilter({
options: [2100, 2103, 2105], // if options defined, will render number select instead of number input
delay: 600, // how long will trigger filtering after user typing, default is 500 ms
placeholder: 'custom placeholder', // placeholder for number input
withoutEmptyComparatorOption: true, // dont render empty option for comparator
withoutEmptyNumberOption: true, // dont render empty option for numner select if it is defined
comparators: [Comparator.EQ, Comparator.GT, Comparator.LT], // Custom the comparators
style: { display: 'inline-grid' }, // custom the style on number filter
className: 'custom-numberfilter-class', // custom the class on number filter
comparatorStyle: { backgroundColor: 'antiquewhite' }, // custom the style on comparator select
comparatorClassName: 'custom-comparator-class', // custom the class on comparator select
numberStyle: { backgroundColor: 'cadetblue', margin: '0px' }, // custom the style on number input/select
numberClassName: 'custom-number-class', // custom the class on ber input/select
defaultValue: { number: 2103, comparator: Comparator.GT } // default value
})
// omit...
```

View File

@ -1,5 +1,6 @@
import TextFilter from './src/components/text';
import SelectFilter from './src/components/select';
import NumberFilter from './src/components/number';
import wrapperFactory from './src/wrapper';
import * as Comparison from './src/comparison';
@ -19,3 +20,8 @@ export const selectFilter = (props = {}) => ({
Filter: SelectFilter,
props
});
export const numberFilter = (props = {}) => ({
Filter: NumberFilter,
props
});

View File

@ -1,2 +1,7 @@
export const LIKE = 'LIKE';
export const EQ = '=';
export const NE = '!=';
export const GT = '>';
export const GE = '>=';
export const LT = '<';
export const LE = '<=';

View File

@ -0,0 +1,249 @@
/* eslint no-return-assign: 0 */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import * as Comparator from '../comparison';
import { FILTER_TYPE, FILTER_DELAY } from '../const';
const legalComparators = [
Comparator.EQ,
Comparator.NE,
Comparator.GT,
Comparator.GE,
Comparator.LT,
Comparator.LE
];
class NumberFilter extends Component {
constructor(props) {
super(props);
this.comparators = props.comparators || legalComparators;
this.timeout = null;
let isSelected = props.defaultValue !== undefined && props.defaultValue.number !== undefined;
if (props.options && isSelected) {
isSelected = props.options.indexOf(props.defaultValue.number) > -1;
}
this.state = { isSelected };
this.onChangeNumber = this.onChangeNumber.bind(this);
this.onChangeNumberSet = this.onChangeNumberSet.bind(this);
this.onChangeComparator = this.onChangeComparator.bind(this);
}
componentDidMount() {
const { column, onFilter } = this.props;
const comparator = this.numberFilterComparator.value;
const number = this.numberFilter.value;
if (comparator && number) {
onFilter(column, { number, comparator }, FILTER_TYPE.NUMBER);
}
}
componentWillUnmount() {
clearTimeout(this.timeout);
}
onChangeNumber(e) {
const { delay, column, onFilter } = this.props;
const comparator = this.numberFilterComparator.value;
if (comparator === '') {
return;
}
if (this.timeout) {
clearTimeout(this.timeout);
}
const filterValue = e.target.value;
this.timeout = setTimeout(() => {
onFilter(column, { number: filterValue, comparator }, FILTER_TYPE.NUMBER);
}, delay);
}
onChangeNumberSet(e) {
const { column, onFilter } = this.props;
const comparator = this.numberFilterComparator.value;
const { value } = e.target;
this.setState(() => ({ isSelected: (value !== '') }));
// if (comparator === '') {
// return;
// }
onFilter(column, { number: value, comparator }, FILTER_TYPE.NUMBER);
}
onChangeComparator(e) {
const { column, onFilter } = this.props;
const value = this.numberFilter.value;
const comparator = e.target.value;
// if (value === '') {
// return;
// }
onFilter(column, { number: value, comparator }, FILTER_TYPE.NUMBER);
}
getComparatorOptions() {
const optionTags = [];
const { withoutEmptyComparatorOption } = this.props;
if (!withoutEmptyComparatorOption) {
optionTags.push(<option key="-1" />);
}
for (let i = 0; i < this.comparators.length; i += 1) {
optionTags.push(
<option key={ i } value={ this.comparators[i] }>
{ this.comparators[i] }
</option>
);
}
return optionTags;
}
getNumberOptions() {
const optionTags = [];
const { options, column, withoutEmptyNumberOption } = this.props;
if (!withoutEmptyNumberOption) {
optionTags.push(
<option key="-1" value="">
{ this.props.placeholder || `Select ${column.text}...` }
</option>
);
}
for (let i = 0; i < options.length; i += 1) {
optionTags.push(<option key={ i } value={ options[i] }>{ options[i] }</option>);
}
return optionTags;
}
applyFilter(filterObj) {
const { column, onFilter } = this.props;
const { number, comparator } = filterObj;
this.setState(() => ({ isSelected: (number !== '') }));
this.numberFilterComparator.value = comparator;
this.numberFilter.value = number;
onFilter(column, { number, comparator }, FILTER_TYPE.NUMBER);
}
cleanFiltered() {
const { column, onFilter, defaultValue } = this.props;
const value = defaultValue ? defaultValue.number : '';
const comparator = defaultValue ? defaultValue.comparator : '';
this.setState(() => ({ isSelected: (value !== '') }));
this.numberFilterComparator.value = comparator;
this.numberFilter.value = value;
onFilter(column, { number: value, comparator }, FILTER_TYPE.NUMBER);
}
render() {
const { isSelected } = this.state;
const {
defaultValue,
column,
options,
style,
className,
numberStyle,
numberClassName,
comparatorStyle,
comparatorClassName,
placeholder
} = this.props;
const selectClass = `
select-filter
number-filter-input
form-control
${numberClassName}
${!isSelected ? 'placeholder-selected' : ''}
`;
return (
<div className={ `filter number-filter ${className}` } style={ style }>
<select
ref={ n => this.numberFilterComparator = n }
style={ comparatorStyle }
className={ `number-filter-comparator form-control ${comparatorClassName}` }
onChange={ this.onChangeComparator }
defaultValue={ defaultValue ? defaultValue.comparator : '' }
>
{ this.getComparatorOptions() }
</select>
{
options ?
<select
ref={ n => this.numberFilter = n }
style={ numberStyle }
className={ selectClass }
onChange={ this.onChangeNumberSet }
defaultValue={ defaultValue ? defaultValue.number : '' }
>
{ this.getNumberOptions() }
</select> :
<input
ref={ n => this.numberFilter = n }
type="number"
style={ numberStyle }
className={ `number-filter-input form-control ${numberClassName}` }
placeholder={ placeholder || `Enter ${column.text}...` }
onChange={ this.onChangeNumber }
defaultValue={ defaultValue ? defaultValue.number : '' }
/>
}
</div>
);
}
}
NumberFilter.propTypes = {
onFilter: PropTypes.func.isRequired,
column: PropTypes.object.isRequired,
options: PropTypes.arrayOf(PropTypes.number),
defaultValue: PropTypes.shape({
number: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
comparator: PropTypes.oneOf([...legalComparators, ''])
}),
delay: PropTypes.number,
/* eslint consistent-return: 0 */
comparators: (props, propName) => {
if (!props[propName]) {
return;
}
for (let i = 0; i < props[propName].length; i += 1) {
let comparatorIsValid = false;
for (let j = 0; j < legalComparators.length; j += 1) {
if (legalComparators[j] === props[propName][i] || props[propName][i] === '') {
comparatorIsValid = true;
break;
}
}
if (!comparatorIsValid) {
return new Error(`Number comparator provided is not supported.
Use only ${legalComparators}`);
}
}
},
placeholder: PropTypes.string,
withoutEmptyComparatorOption: PropTypes.bool,
withoutEmptyNumberOption: PropTypes.bool,
style: PropTypes.object,
className: PropTypes.string,
comparatorStyle: PropTypes.object,
comparatorClassName: PropTypes.string,
numberStyle: PropTypes.object,
numberClassName: PropTypes.string
};
NumberFilter.defaultProps = {
delay: FILTER_DELAY,
options: undefined,
defaultValue: {
number: undefined,
comparator: ''
},
withoutEmptyComparatorOption: false,
withoutEmptyNumberOption: false,
comparators: legalComparators,
placeholder: undefined,
style: undefined,
className: '',
comparatorStyle: undefined,
comparatorClassName: '',
numberStyle: undefined,
numberClassName: ''
};
export default NumberFilter;

View File

@ -1,6 +1,7 @@
export const FILTER_TYPE = {
TEXT: 'TEXT',
SELECT: 'SELECT'
SELECT: 'SELECT',
NUMBER: 'NUMBER'
};
export const FILTER_DELAY = 500;

View File

@ -1,5 +1,7 @@
/* eslint eqeqeq: 0 */
/* eslint no-console: 0 */
import { FILTER_TYPE } from './const';
import { LIKE, EQ } from './comparison';
import { LIKE, EQ, NE, GT, GE, LT, LE } from './comparison';
export const filterByText = _ => (
data,
@ -19,12 +21,75 @@ export const filterByText = _ => (
return cellStr.indexOf(filterVal) > -1;
});
export const filterByNumber = _ => (
data,
dataField,
{ filterVal: { comparator, number } },
customFilterValue
) =>
data.filter((row) => {
if (number === '' || !comparator) return true;
let valid = true;
let cell = _.get(row, dataField);
if (customFilterValue) {
cell = customFilterValue(cell, row);
}
switch (comparator) {
case EQ: {
if (cell != number) {
valid = false;
}
break;
}
case GT: {
if (cell <= number) {
valid = false;
}
break;
}
case GE: {
if (cell < number) {
valid = false;
}
break;
}
case LT: {
if (cell >= number) {
valid = false;
}
break;
}
case LE: {
if (cell > number) {
valid = false;
}
break;
}
case NE: {
if (cell == number) {
valid = false;
}
break;
}
default: {
console.error('Number comparator provided is not supported');
break;
}
}
return valid;
});
export const filterFactory = _ => (filterType) => {
let filterFn;
switch (filterType) {
case FILTER_TYPE.TEXT:
case FILTER_TYPE.SELECT:
filterFn = filterByText(_);
break;
case FILTER_TYPE.NUMBER:
filterFn = filterByNumber(_);
break;
default:
filterFn = filterByText(_);
}

View File

@ -3,7 +3,9 @@
}
.react-bootstrap-table > table > thead > tr > th .select-filter option[value=''],
.react-bootstrap-table > table > thead > tr > th .select-filter.placeholder-selected {
.react-bootstrap-table > table > thead > tr > th .select-filter.placeholder-selected,
.react-bootstrap-table > table > thead > tr > th .filter::-webkit-input-placeholder,
.react-bootstrap-table > table > thead > tr > th .number-filter-input::-webkit-input-placeholder {
color: lightgrey;
font-style: italic;
}
@ -11,4 +13,19 @@
.react-bootstrap-table > table > thead > tr > th .select-filter.placeholder-selected option:not([value='']) {
color: initial;
font-style: initial;
}
.react-bootstrap-table > table > thead > tr > th .number-filter {
display: flex;
}
.react-bootstrap-table > table > thead > tr > th .number-filter-input {
margin-left: 5px;
float: left;
width: calc(100% - 67px - 5px);
}
.react-bootstrap-table > table > thead > tr > th .number-filter-comparator {
width: 67px;
float: left;
}

View File

@ -0,0 +1,310 @@
import 'jsdom-global/register';
import React from 'react';
import sinon from 'sinon';
import { mount } from 'enzyme';
import NumberFilter from '../../src/components/number';
import { FILTER_TYPE } from '../../src/const';
import * as Comparator from '../../src/comparison';
describe('Number Filter', () => {
let wrapper;
const onFilter = sinon.stub();
const column = {
dataField: 'price',
text: 'Product Price'
};
afterEach(() => {
onFilter.reset();
});
describe('initialization', () => {
beforeEach(() => {
wrapper = mount(
<NumberFilter onFilter={ onFilter } column={ column } />
);
});
it('should have correct state', () => {
expect(wrapper.state().isSelected).toBeFalsy();
});
it('should rendering component successfully', () => {
expect(wrapper).toHaveLength(1);
expect(wrapper.find('select')).toHaveLength(1);
expect(wrapper.find('input[type="number"]')).toHaveLength(1);
expect(wrapper.find('.number-filter')).toHaveLength(1);
});
it('should rendering comparator options correctly', () => {
const select = wrapper.find('select');
expect(select.find('option')).toHaveLength(wrapper.prop('comparators').length + 1);
});
});
describe('when withoutEmptyComparatorOption prop is true', () => {
beforeEach(() => {
wrapper = mount(
<NumberFilter onFilter={ onFilter } column={ column } withoutEmptyComparatorOption />
);
});
it('should rendering comparator options correctly', () => {
const select = wrapper.find('select');
expect(select.find('option')).toHaveLength(wrapper.prop('comparators').length);
});
});
describe('when defaultValue.number props is defined', () => {
const number = 203;
beforeEach(() => {
wrapper = mount(
<NumberFilter onFilter={ onFilter } column={ column } defaultValue={ { number } } />
);
});
it('should rendering input successfully', () => {
expect(wrapper).toHaveLength(1);
const input = wrapper.find('input[type="number"]');
expect(input).toHaveLength(1);
expect(input.props().defaultValue).toEqual(number);
});
});
describe('when defaultValue.comparator props is defined', () => {
const comparator = Comparator.EQ;
beforeEach(() => {
wrapper = mount(
<NumberFilter onFilter={ onFilter } column={ column } defaultValue={ { comparator } } />
);
});
it('should rendering comparator select successfully', () => {
expect(wrapper).toHaveLength(1);
const select = wrapper.find('.number-filter-comparator');
expect(select).toHaveLength(1);
expect(select.props().defaultValue).toEqual(comparator);
});
});
describe('when defaultValue.number and defaultValue.comparator props is defined', () => {
const number = 203;
const comparator = Comparator.EQ;
beforeEach(() => {
wrapper = mount(
<NumberFilter
onFilter={ onFilter }
column={ column }
defaultValue={ { number, comparator } }
/>
);
});
it('should have correct state', () => {
expect(wrapper.state().isSelected).toBeTruthy();
});
it('should calling onFilter on componentDidMount', () => {
expect(onFilter.calledOnce).toBeTruthy();
expect(onFilter.calledWith(
column, { number: `${number}`, comparator }, FILTER_TYPE.NUMBER)).toBeTruthy();
});
});
describe('when options props is defined', () => {
const options = [2100, 2103, 2105];
beforeEach(() => {
wrapper = mount(
<NumberFilter
onFilter={ onFilter }
column={ column }
options={ options }
/>
);
});
it('should rendering number options instead of number input', () => {
expect(wrapper).toHaveLength(1);
const select = wrapper.find('.select-filter.placeholder-selected');
expect(select).toHaveLength(1);
expect(select.find('option')).toHaveLength(options.length + 1);
});
describe('when withoutEmptyNumberOption props is defined', () => {
beforeEach(() => {
wrapper = mount(
<NumberFilter
onFilter={ onFilter }
column={ column }
options={ options }
withoutEmptyNumberOption
/>
);
});
it('should rendering number options instead of number input', () => {
const select = wrapper.find('.select-filter.placeholder-selected');
expect(select).toHaveLength(1);
expect(select.find('option')).toHaveLength(options.length);
});
});
describe('when defaultValue.number props is defined', () => {
const number = 203;
beforeEach(() => {
wrapper = mount(
<NumberFilter
onFilter={ onFilter }
column={ column }
defaultValue={ { number } }
options={ options }
/>
);
});
it('should rendering number options successfully', () => {
const select = wrapper.find('.select-filter.placeholder-selected');
expect(select).toHaveLength(1);
expect(select.props().defaultValue).toEqual(number);
});
});
describe('when defaultValue.number and defaultValue.comparator props is defined', () => {
const number = options[1];
const comparator = Comparator.EQ;
beforeEach(() => {
wrapper = mount(
<NumberFilter
onFilter={ onFilter }
column={ column }
defaultValue={ { number, comparator } }
options={ options }
/>
);
});
it('should rendering number options successfully', () => {
let select = wrapper.find('.placeholder-selected');
expect(select).toHaveLength(0);
select = wrapper.find('.select-filter');
expect(select).toHaveLength(1);
});
});
});
describe('when style props is defined', () => {
const style = { backgroundColor: 'red' };
beforeEach(() => {
wrapper = mount(
<NumberFilter
onFilter={ onFilter }
column={ column }
style={ style }
/>
);
});
it('should rendering component successfully', () => {
expect(wrapper).toHaveLength(1);
expect(wrapper.find('.number-filter').prop('style')).toEqual(style);
});
});
describe('when numberStyle props is defined', () => {
const numberStyle = { backgroundColor: 'red' };
beforeEach(() => {
wrapper = mount(
<NumberFilter
onFilter={ onFilter }
column={ column }
numberStyle={ numberStyle }
/>
);
});
it('should rendering component successfully', () => {
expect(wrapper).toHaveLength(1);
expect(wrapper.find('.number-filter-input').prop('style')).toEqual(numberStyle);
});
});
describe('when comparatorStyle props is defined', () => {
const comparatorStyle = { backgroundColor: 'red' };
beforeEach(() => {
wrapper = mount(
<NumberFilter
onFilter={ onFilter }
column={ column }
comparatorStyle={ comparatorStyle }
/>
);
});
it('should rendering component successfully', () => {
expect(wrapper).toHaveLength(1);
expect(wrapper.find('select').prop('style')).toEqual(comparatorStyle);
});
});
describe('when className props is defined', () => {
const className = 'test';
beforeEach(() => {
wrapper = mount(
<NumberFilter
onFilter={ onFilter }
column={ column }
className={ className }
/>
);
});
it('should rendering component successfully', () => {
expect(wrapper).toHaveLength(1);
expect(wrapper.hasClass(className)).toBeTruthy();
});
});
describe('when numberClassName props is defined', () => {
const className = 'test';
beforeEach(() => {
wrapper = mount(
<NumberFilter
onFilter={ onFilter }
column={ column }
numberClassName={ className }
/>
);
});
it('should rendering component successfully', () => {
expect(wrapper).toHaveLength(1);
expect(wrapper.find('.number-filter-input').prop('className').indexOf(className) > -1).toBeTruthy();
});
});
describe('when comparatorClassName props is defined', () => {
const className = 'test';
beforeEach(() => {
wrapper = mount(
<NumberFilter
onFilter={ onFilter }
column={ column }
comparatorClassName={ className }
/>
);
});
it('should rendering component successfully', () => {
expect(wrapper).toHaveLength(1);
expect(wrapper.find('select').prop('className').indexOf(className) > -1).toBeTruthy();
});
});
});

View File

@ -4,7 +4,7 @@ import Store from 'react-bootstrap-table-next/src/store';
import { filters } from '../src/filter';
import { FILTER_TYPE } from '../src/const';
import { LIKE, EQ } from '../src/comparison';
import { LIKE, EQ, GT, GE, LT, LE, NE } from '../src/comparison';
const data = [];
for (let i = 0; i < 20; i += 1) {
@ -37,7 +37,7 @@ describe('filter', () => {
}];
});
describe('text filter', () => {
describe('filterByText', () => {
beforeEach(() => {
filterFn = filters(store, columns, _);
});
@ -91,4 +91,114 @@ describe('filter', () => {
});
});
});
describe('filterByNumber', () => {
beforeEach(() => {
filterFn = filters(store, columns, _);
});
describe('when currFilters.filterVal.comparator is empty', () => {
it('should returning correct result', () => {
currFilters.price = {
filterVal: { comparator: '', number: '203' },
filterType: FILTER_TYPE.NUMBER
};
let result = filterFn(currFilters);
expect(result).toHaveLength(data.length);
currFilters.price.filterVal.comparator = undefined;
result = filterFn(currFilters);
expect(result).toHaveLength(data.length);
});
});
describe('when currFilters.filterVal.number is empty', () => {
it('should returning correct result', () => {
currFilters.price = {
filterVal: { comparator: EQ, number: '' },
filterType: FILTER_TYPE.NUMBER
};
const result = filterFn(currFilters);
expect(result).toHaveLength(data.length);
});
});
describe(`when currFilters.filterVal.comparator is ${EQ}`, () => {
it('should returning correct result', () => {
currFilters.price = {
filterVal: { comparator: EQ, number: '203' },
filterType: FILTER_TYPE.NUMBER
};
let result = filterFn(currFilters);
expect(result).toHaveLength(1);
currFilters.price.filterVal.number = '0';
result = filterFn(currFilters);
expect(result).toHaveLength(0);
});
});
describe(`when currFilters.filterVal.comparator is ${GT}`, () => {
it('should returning correct result', () => {
currFilters.price = {
filterVal: { comparator: GT, number: '203' },
filterType: FILTER_TYPE.NUMBER
};
const result = filterFn(currFilters);
expect(result).toHaveLength(16);
});
});
describe(`when currFilters.filterVal.comparator is ${GE}`, () => {
it('should returning correct result', () => {
currFilters.price = {
filterVal: { comparator: GE, number: '203' },
filterType: FILTER_TYPE.NUMBER
};
const result = filterFn(currFilters);
expect(result).toHaveLength(17);
});
});
describe(`when currFilters.filterVal.comparator is ${LT}`, () => {
it('should returning correct result', () => {
currFilters.price = {
filterVal: { comparator: LT, number: '203' },
filterType: FILTER_TYPE.NUMBER
};
const result = filterFn(currFilters);
expect(result).toHaveLength(3);
});
});
describe(`when currFilters.filterVal.comparator is ${LE}`, () => {
it('should returning correct result', () => {
currFilters.price = {
filterVal: { comparator: LE, number: '203' },
filterType: FILTER_TYPE.NUMBER
};
const result = filterFn(currFilters);
expect(result).toHaveLength(4);
});
});
describe(`when currFilters.filterVal.comparator is ${NE}`, () => {
it('should returning correct result', () => {
currFilters.price = {
filterVal: { comparator: NE, number: '203' },
filterType: FILTER_TYPE.NUMBER
};
const result = filterFn(currFilters);
expect(result).toHaveLength(19);
});
});
});
});