mirror of
https://github.com/gosticks/react-bootstrap-table2.git
synced 2026-07-02 23:20:13 +00:00
fix #63 (part1 - cell editing validation)
* implement cell editing validation * add test cases for cell editing validation * add story for validator for cell editor * add docs for cell editor validation
This commit is contained in:
@@ -42,6 +42,7 @@ Following is a `cellEdit` object:
|
||||
{
|
||||
mode: 'click',
|
||||
blurToSave: true,
|
||||
timeToCloseMessage: 2500,
|
||||
onEditing: (rowId, dataField, newValue) => { ... },
|
||||
beforeSaveCell: (oldValue, newValue, row, column) => { ... },
|
||||
afterSaveCell: (oldValue, newValue, row, column) => { ... },
|
||||
@@ -49,10 +50,13 @@ Following is a `cellEdit` object:
|
||||
}
|
||||
```
|
||||
#### <a name='cellEdit.mode'>cellEdit.mode - [String]</a>
|
||||
`cellEdit.mode` possible value is `click` and `dbclick`. It's required value that tell `react-bootstrap-table2` how to trigger the cell editing.
|
||||
`cellEdit.mode` possible value is `click` and `dbclick`. **It's required value** that tell `react-bootstrap-table2` how to trigger the cell editing.
|
||||
|
||||
#### <a name='cellEdit.blurToSave'>cellEdit.blurToSave - [Bool]</a>
|
||||
Default is `false`, enable it will be able to save the cell automatically when blur from the cell editor.
|
||||
|
||||
#### <a name='cellEdit.nonEditableRows'>cellEdit.nonEditableRows - [Function]</a>
|
||||
`cellEdit.nonEditableRows` accept a callback function and expect return an array which used to restrict all the columns of some rows as non-editable. So the each item in return array should be rowkey(`keyField`)
|
||||
|
||||
#### <a name='cellEdit.timeToCloseMessage'>cellEdit.timeToCloseMessage - [Function]</a>
|
||||
If a [`column.validator`](./columns.md#validator) defined and the new value is invalid, `react-bootstrap-table2` will popup a alert at the bottom of editor. `cellEdit.timeToCloseMessage` is a chance to let you decide how long the alert should be stay. Default is 3000 millisecond.
|
||||
@@ -26,6 +26,7 @@ Available properties in a column object:
|
||||
* [headerAlign](#headerAlign)
|
||||
* [headerAttrs](#headerAttrs)
|
||||
* [editable](#editable)
|
||||
* [validator](#validator)
|
||||
|
||||
Following is a most simplest and basic usage:
|
||||
|
||||
@@ -417,4 +418,25 @@ A new `Object` will be the result of element headerAttrs.
|
||||
> overwrited when other props related to HTML attributes were given.
|
||||
|
||||
## <a name='editable'>column.editable - [Bool]</a>
|
||||
`column.editable` default is true, means every column is editable if you configure [`cellEdit`](./README.md#cellEdit). But you can disable some columns editable via setting `false`.
|
||||
`column.editable` default is true, means every column is editable if you configure [`cellEdit`](./README.md#cellEdit). But you can disable some columns editable via setting `false`.
|
||||
|
||||
## <a name='validator'>column.validator - [Function]</a>
|
||||
`column.validator` used for validate the data when cell on updating. it's should accept a callback function with following argument:
|
||||
`newValue`, `row` and `column`:
|
||||
|
||||
```js
|
||||
{
|
||||
// omit...
|
||||
validator: (newValue, row, column) => {
|
||||
return ...;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The return value can be a bool or an object. If your valiation is pass, return `true` explicitly. If your valiation is invalid, return following object instead:
|
||||
```js
|
||||
{
|
||||
valid: false,
|
||||
message: 'SOME_REASON_HERE'
|
||||
}
|
||||
```
|
||||
85
packages/react-bootstrap-table2-example/examples/cell-edit/cell-edit-validator-table.js
vendored
Normal file
85
packages/react-bootstrap-table2-example/examples/cell-edit/cell-edit-validator-table.js
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
import React from 'react';
|
||||
/* eslint no-unused-vars: 0 */
|
||||
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'
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name'
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price',
|
||||
validator: (newValue, row, column) => {
|
||||
if (isNaN(newValue)) {
|
||||
return {
|
||||
valid: false,
|
||||
message: 'Price should be numeric'
|
||||
};
|
||||
}
|
||||
if (newValue < 2000) {
|
||||
return {
|
||||
valid: false,
|
||||
message: 'Price should bigger than 2000'
|
||||
};
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}];
|
||||
|
||||
const sourceCode = `\
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID'
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name'
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price',
|
||||
validator: (newValue, row, column) => {
|
||||
if (isNaN(newValue)) {
|
||||
return {
|
||||
valid: false,
|
||||
message: 'Price should be numeric'
|
||||
};
|
||||
}
|
||||
if (newValue < 2000) {
|
||||
return {
|
||||
valid: false,
|
||||
message: 'Price should bigger than 2000'
|
||||
};
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}];
|
||||
|
||||
const cellEdit = {
|
||||
mode: 'click',
|
||||
blurToSave: true
|
||||
};
|
||||
|
||||
<BootstrapTableful
|
||||
keyField='id'
|
||||
data={ products }
|
||||
columns={ columns }
|
||||
cellEdit={ cellEdit }
|
||||
/>
|
||||
`;
|
||||
|
||||
const cellEdit = {
|
||||
mode: 'click',
|
||||
blurToSave: true
|
||||
};
|
||||
export default () => (
|
||||
<div>
|
||||
<h3>Product Price should bigger than $2000</h3>
|
||||
<BootstrapTableful keyField="id" data={ products } columns={ columns } cellEdit={ cellEdit } />
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
@@ -42,6 +42,7 @@ import BlurToSaveTable from 'examples/cell-edit/blur-to-save-table';
|
||||
import RowLevelEditableTable from 'examples/cell-edit/row-level-editable-table';
|
||||
import ColumnLevelEditableTable from 'examples/cell-edit/column-level-editable-table';
|
||||
import CellEditHooks from 'examples/cell-edit/cell-edit-hooks-table';
|
||||
import CellEditValidator from 'examples/cell-edit/cell-edit-validator-table';
|
||||
|
||||
// css style
|
||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
@@ -92,4 +93,5 @@ storiesOf('Cell Editing', module)
|
||||
.add('Blur to Save Cell', () => <BlurToSaveTable />)
|
||||
.add('Row Level Editable', () => <RowLevelEditableTable />)
|
||||
.add('Column Level Editable', () => <ColumnLevelEditableTable />)
|
||||
.add('Rich Hook Functions', () => <CellEditHooks />);
|
||||
.add('Rich Hook Functions', () => <CellEditHooks />)
|
||||
.add('Validation', () => <CellEditValidator />);
|
||||
|
||||
@@ -137,7 +137,8 @@ BootstrapTable.propTypes = {
|
||||
blurToSave: PropTypes.bool,
|
||||
beforeSaveCell: PropTypes.func,
|
||||
afterSaveCell: PropTypes.func,
|
||||
nonEditableRows: PropTypes.func
|
||||
nonEditableRows: PropTypes.func,
|
||||
timeToCloseMessage: PropTypes.number
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
3
packages/react-bootstrap-table2/src/const.js
vendored
3
packages/react-bootstrap-table2/src/const.js
vendored
@@ -3,5 +3,6 @@ export default {
|
||||
SORT_DESC: 'desc',
|
||||
UNABLE_TO_CELL_EDIT: 'none',
|
||||
CLICK_TO_CELL_EDIT: 'click',
|
||||
DBCLICK_TO_CELL_EDIT: 'dbclick'
|
||||
DBCLICK_TO_CELL_EDIT: 'dbclick',
|
||||
TIME_TO_CLOSE_MESSAGE: 3000
|
||||
};
|
||||
|
||||
@@ -1,33 +1,73 @@
|
||||
/* eslint arrow-body-style: 0 */
|
||||
/* eslint react/prop-types: 0 */
|
||||
/* eslint no-return-assign: 0 */
|
||||
import React, { Component } from 'react';
|
||||
import cs from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import _ from './utils';
|
||||
import Const from './const';
|
||||
import TextEditor from './text-editor';
|
||||
import EditorIndicator from './editor-indicator';
|
||||
|
||||
class EditingCell extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.indicatorTimer = null;
|
||||
this.clearTimer = this.clearTimer.bind(this);
|
||||
this.handleBlur = this.handleBlur.bind(this);
|
||||
this.handleKeyDown = this.handleKeyDown.bind(this);
|
||||
this.beforeComplete = this.beforeComplete.bind(this);
|
||||
this.state = {
|
||||
invalidMessage: null
|
||||
};
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.clearTimer();
|
||||
}
|
||||
|
||||
clearTimer() {
|
||||
if (this.indicatorTimer) {
|
||||
clearTimeout(this.indicatorTimer);
|
||||
}
|
||||
}
|
||||
|
||||
beforeComplete(row, column, newValue) {
|
||||
this.clearTimer();
|
||||
const { onComplete, timeToCloseMessage } = this.props;
|
||||
if (_.isFunction(column.validator)) {
|
||||
const validateForm = column.validator(newValue, row, column);
|
||||
if (_.isObject(validateForm) && !validateForm.valid) {
|
||||
this.setState(() => {
|
||||
return { invalidMessage: validateForm.message };
|
||||
});
|
||||
this.indicatorTimer = setTimeout(() => {
|
||||
this.setState(() => {
|
||||
return { invalidMessage: null };
|
||||
});
|
||||
}, timeToCloseMessage);
|
||||
return;
|
||||
}
|
||||
}
|
||||
onComplete(row, column, newValue);
|
||||
}
|
||||
|
||||
handleBlur() {
|
||||
const { onEscape, onComplete, blurToSave, row, column } = this.props;
|
||||
const { onEscape, blurToSave, row, column } = this.props;
|
||||
if (blurToSave) {
|
||||
const value = this.editor.text.value;
|
||||
if (!_.isDefined(value)) {
|
||||
// TODO: for other custom or embed editor
|
||||
}
|
||||
onComplete(row, column, value);
|
||||
this.beforeComplete(row, column, value);
|
||||
} else {
|
||||
onEscape();
|
||||
}
|
||||
}
|
||||
|
||||
handleKeyDown(e) {
|
||||
const { onEscape, onComplete, row, column } = this.props;
|
||||
const { onEscape, row, column } = this.props;
|
||||
if (e.keyCode === 27) { // ESC
|
||||
onEscape();
|
||||
} else if (e.keyCode === 13) { // ENTER
|
||||
@@ -35,11 +75,12 @@ class EditingCell extends Component {
|
||||
if (!_.isDefined(value)) {
|
||||
// TODO: for other custom or embed editor
|
||||
}
|
||||
onComplete(row, column, value);
|
||||
this.beforeComplete(row, column, value);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { invalidMessage } = this.state;
|
||||
const { row, column } = this.props;
|
||||
const { dataField } = column;
|
||||
|
||||
@@ -48,9 +89,17 @@ class EditingCell extends Component {
|
||||
onKeyDown: this.handleKeyDown,
|
||||
onBlur: this.handleBlur
|
||||
};
|
||||
|
||||
const editorClass = invalidMessage ? cs('animated', 'shake') : null;
|
||||
return (
|
||||
<td>
|
||||
<TextEditor ref={ node => this.editor = node } defaultValue={ value } { ...editorAttrs } />
|
||||
<td className="react-bootstrap-table-editing-cell">
|
||||
<TextEditor
|
||||
ref={ node => this.editor = node }
|
||||
defaultValue={ value }
|
||||
classNames={ editorClass }
|
||||
{ ...editorAttrs }
|
||||
/>
|
||||
{ invalidMessage ? <EditorIndicator invalidMessage={ invalidMessage } /> : null }
|
||||
</td>
|
||||
);
|
||||
}
|
||||
@@ -60,7 +109,12 @@ EditingCell.propTypes = {
|
||||
row: PropTypes.object.isRequired,
|
||||
column: PropTypes.object.isRequired,
|
||||
onComplete: PropTypes.func.isRequired,
|
||||
onEscape: PropTypes.func.isRequired
|
||||
onEscape: PropTypes.func.isRequired,
|
||||
timeToCloseMessage: PropTypes.number
|
||||
};
|
||||
|
||||
EditingCell.defaultProps = {
|
||||
timeToCloseMessage: Const.TIME_TO_CLOSE_MESSAGE
|
||||
};
|
||||
|
||||
export default EditingCell;
|
||||
|
||||
19
packages/react-bootstrap-table2/src/editor-indicator.js
vendored
Normal file
19
packages/react-bootstrap-table2/src/editor-indicator.js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
/* eslint no-return-assign: 0 */
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const EditorIndicator = ({ invalidMessage }) =>
|
||||
(
|
||||
<div className="alert alert-danger fade in">
|
||||
<strong>{ invalidMessage }</strong>
|
||||
</div>
|
||||
);
|
||||
|
||||
EditorIndicator.propTypes = {
|
||||
invalidMessage: PropTypes.string
|
||||
};
|
||||
|
||||
EditorIndicator.defaultProps = {
|
||||
invalidMessage: null
|
||||
};
|
||||
export default EditorIndicator;
|
||||
@@ -99,7 +99,9 @@ HeaderCell.propTypes = {
|
||||
headerAlign: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||||
align: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||||
sort: PropTypes.bool,
|
||||
sortFunc: PropTypes.func
|
||||
sortFunc: PropTypes.func,
|
||||
editable: PropTypes.bool,
|
||||
validator: PropTypes.func
|
||||
}).isRequired,
|
||||
index: PropTypes.number.isRequired,
|
||||
onSort: PropTypes.func,
|
||||
|
||||
12
packages/react-bootstrap-table2/src/row.js
vendored
12
packages/react-bootstrap-table2/src/row.js
vendored
@@ -16,13 +16,11 @@ const Row = (props) => {
|
||||
editable: editableRow
|
||||
} = props;
|
||||
const {
|
||||
ridx: editingRowIdx,
|
||||
cidx: editingColIdx,
|
||||
mode,
|
||||
onStart,
|
||||
onEscape,
|
||||
onComplete,
|
||||
blurToSave
|
||||
ridx: editingRowIdx,
|
||||
cidx: editingColIdx,
|
||||
...rest
|
||||
} = cellEdit;
|
||||
return (
|
||||
<tr>
|
||||
@@ -36,9 +34,7 @@ const Row = (props) => {
|
||||
key={ _.get(row, column.dataField) }
|
||||
row={ row }
|
||||
column={ column }
|
||||
blurToSave={ blurToSave }
|
||||
onComplete={ onComplete }
|
||||
onEscape={ onEscape }
|
||||
{ ...rest }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* eslint no-return-assign: 0 */
|
||||
import React, { Component } from 'react';
|
||||
import cs from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
class TextEditor extends Component {
|
||||
@@ -10,12 +11,13 @@ class TextEditor extends Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { defaultValue, ...rest } = this.props;
|
||||
const { defaultValue, classNames, ...rest } = this.props;
|
||||
const editorClass = cs('form-control editor edit-text', classNames);
|
||||
return (
|
||||
<input
|
||||
ref={ node => this.text = node }
|
||||
type="text"
|
||||
className="form-control editor edit-text"
|
||||
className={ editorClass }
|
||||
{ ...rest }
|
||||
/>
|
||||
);
|
||||
@@ -23,9 +25,16 @@ class TextEditor extends Component {
|
||||
}
|
||||
|
||||
TextEditor.propTypes = {
|
||||
classNames: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.object
|
||||
]),
|
||||
defaultValue: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.number
|
||||
]).isRequired
|
||||
};
|
||||
TextEditor.defaultProps = {
|
||||
classNames: null
|
||||
};
|
||||
export default TextEditor;
|
||||
|
||||
@@ -25,4 +25,94 @@
|
||||
td.react-bs-table-no-data {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
td.react-bootstrap-table-editing-cell {
|
||||
.animated {
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
.animated.bounceIn,
|
||||
.animated.bounceOut{
|
||||
animation-duration: .75s;
|
||||
}
|
||||
|
||||
.animated.shake{
|
||||
animation-duration: .3s;
|
||||
}
|
||||
|
||||
@keyframes shake {
|
||||
from, to {
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
10%, 50%, 90% {
|
||||
transform: translate3d(-10px, 0, 0);
|
||||
}
|
||||
|
||||
30%, 70%{
|
||||
transform: translate3d(10px, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
.shake {
|
||||
animation-name: shake;
|
||||
}
|
||||
|
||||
@keyframes bounceIn {
|
||||
from, 20%, 40%, 60%, 80%, to {
|
||||
animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
|
||||
}
|
||||
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: scale3d(.3, .3, .3);
|
||||
}
|
||||
|
||||
20% {
|
||||
transform: scale3d(1.1, 1.1, 1.1);
|
||||
}
|
||||
|
||||
40% {
|
||||
transform: scale3d(.9, .9, .9);
|
||||
}
|
||||
|
||||
60% {
|
||||
opacity: 1;
|
||||
transform: scale3d(1.03, 1.03, 1.03);
|
||||
}
|
||||
|
||||
80% {
|
||||
transform: scale3d(.97, .97, .97);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
.bounceIn {
|
||||
animation-name: bounceIn;
|
||||
}
|
||||
|
||||
@keyframes bounceOut {
|
||||
20% {
|
||||
transform: scale3d(.9, .9, .9);
|
||||
}
|
||||
|
||||
50%, 55% {
|
||||
opacity: 1;
|
||||
transform: scale3d(1.1, 1.1, 1.1);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: scale3d(.3, .3, .3);
|
||||
}
|
||||
}
|
||||
|
||||
.bounceOut {
|
||||
animation-name: bounceOut;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import { shallow, mount } from 'enzyme';
|
||||
import { TableRowWrapper } from './test-helpers/table-wrapper';
|
||||
import EditingCell from '../src/editing-cell';
|
||||
import TextEditor from '../src/text-editor';
|
||||
import EditorIndicator from '../src/editor-indicator';
|
||||
|
||||
|
||||
describe('EditingCell', () => {
|
||||
@@ -17,7 +18,7 @@ describe('EditingCell', () => {
|
||||
name: 'A'
|
||||
};
|
||||
|
||||
const column = {
|
||||
let column = {
|
||||
dataField: 'id',
|
||||
text: 'ID'
|
||||
};
|
||||
@@ -39,6 +40,7 @@ describe('EditingCell', () => {
|
||||
expect(wrapper.length).toBe(1);
|
||||
expect(wrapper.find('td').length).toBe(1);
|
||||
expect(wrapper.find(TextEditor).length).toBe(1);
|
||||
expect(wrapper.state().invalidMessage).toBeNull();
|
||||
});
|
||||
|
||||
it('should render TextEditor with correct props', () => {
|
||||
@@ -46,6 +48,12 @@ describe('EditingCell', () => {
|
||||
expect(textEditor.props().defaultValue).toEqual(row[column.dataField]);
|
||||
expect(textEditor.props().onKeyDown).toBeDefined();
|
||||
expect(textEditor.props().onBlur).toBeDefined();
|
||||
expect(textEditor.props().classNames).toBeNull();
|
||||
});
|
||||
|
||||
it('should not render EditorIndicator due to state.invalidMessage is null', () => {
|
||||
const indicator = wrapper.find(EditorIndicator);
|
||||
expect(indicator.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('when press ENTER on TextEditor should call onComplete correctly', () => {
|
||||
@@ -90,4 +98,76 @@ describe('EditingCell', () => {
|
||||
expect(onComplete.calledWith(row, column, `${row[column.dataField]}`)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when column.validator is defined', () => {
|
||||
let newValue;
|
||||
let validForm;
|
||||
let validatorCallBack;
|
||||
|
||||
describe('and column.validator return an object', () => {
|
||||
beforeEach(() => {
|
||||
newValue = 'newValue';
|
||||
validForm = { valid: false, message: 'Something is invalid' };
|
||||
validatorCallBack = sinon.stub().returns(validForm);
|
||||
column = {
|
||||
dataField: 'id',
|
||||
text: 'ID',
|
||||
validator: validatorCallBack
|
||||
};
|
||||
wrapper.instance().beforeComplete(row, column, newValue);
|
||||
});
|
||||
|
||||
it('should call column.validator successfully', () => {
|
||||
expect(validatorCallBack.callCount).toBe(1);
|
||||
expect(validatorCallBack.calledWith(newValue, row, column)).toBe(true);
|
||||
});
|
||||
|
||||
it('should not call onComplete', () => {
|
||||
expect(onComplete.callCount).toBe(0);
|
||||
});
|
||||
|
||||
it('should set indicatorTimer successfully', () => {
|
||||
expect(wrapper.instance().indicatorTimer).toBeDefined();
|
||||
});
|
||||
|
||||
it('should set invalidMessage state correctly', () => {
|
||||
expect(wrapper.state().invalidMessage).toEqual(validForm.message);
|
||||
});
|
||||
|
||||
it('should render TextEditor with correct shake and animated class', () => {
|
||||
const editor = wrapper.find(TextEditor);
|
||||
expect(editor.length).toEqual(1);
|
||||
expect(editor.props().classNames).toEqual('animated shake');
|
||||
});
|
||||
|
||||
it('should render EditorIndicator correctly', () => {
|
||||
const indicator = wrapper.find(EditorIndicator);
|
||||
expect(indicator.length).toEqual(1);
|
||||
expect(indicator.props().invalidMessage).toEqual(validForm.message);
|
||||
});
|
||||
});
|
||||
|
||||
describe('and column.validator return true or something', () => {
|
||||
beforeEach(() => {
|
||||
newValue = 'newValue';
|
||||
validForm = true;
|
||||
validatorCallBack = sinon.stub().returns(validForm);
|
||||
column = {
|
||||
dataField: 'id',
|
||||
text: 'ID',
|
||||
validator: validatorCallBack
|
||||
};
|
||||
wrapper.instance().beforeComplete(row, column, newValue);
|
||||
});
|
||||
|
||||
it('should call column.validator successfully', () => {
|
||||
expect(validatorCallBack.callCount).toBe(1);
|
||||
expect(validatorCallBack.calledWith(newValue, row, column)).toBe(true);
|
||||
});
|
||||
|
||||
it('should call onComplete', () => {
|
||||
expect(onComplete.callCount).toBe(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,4 +21,21 @@ describe('TextEditor', () => {
|
||||
expect(wrapper.find('input').prop('type')).toEqual('text');
|
||||
expect(wrapper.find('.form-control.editor.edit-text').length).toBe(1);
|
||||
});
|
||||
|
||||
describe('whenclassNames prop defined', () => {
|
||||
const className = 'test-class';
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(
|
||||
<TextEditor
|
||||
defaultValue={ value }
|
||||
classNames={ className }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
it('should render correct custom classname', () => {
|
||||
expect(wrapper.length).toBe(1);
|
||||
expect(wrapper.find(`.${className}`).length).toBe(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user