mirror of
https://github.com/gosticks/react-bootstrap-table2.git
synced 2025-10-16 11:55:39 +00:00
patch tests for refining remote cell edit
This commit is contained in:
parent
a50a12426a
commit
beafef9661
@ -1,75 +0,0 @@
|
||||
/* eslint no-unused-vars: 0 */
|
||||
/* eslint arrow-body-style: 0 */
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import BootstrapTable from 'react-bootstrap-table2';
|
||||
import Code from 'components/common/code-block';
|
||||
import { productsGenerator, sleep } from 'utils/common';
|
||||
|
||||
const products = productsGenerator();
|
||||
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID'
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name'
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price'
|
||||
}];
|
||||
|
||||
const sourceCode = `\
|
||||
class CellEditWithPromise extends Component {
|
||||
handleCellEditing = (rowId, dataField, newValue) => {
|
||||
return sleep(1000).then(() => {
|
||||
if (dataField === 'price' && (newValue < 2000 || isNaN(newValue))) {
|
||||
throw new Error('Product Price should bigger than $2000');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const cellEdit = {
|
||||
mode: 'click',
|
||||
blurToSave: true,
|
||||
onUpdate: this.handleCellEditing
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<BootstrapTable keyField="id" data={ products } columns={ columns } cellEdit={ cellEdit } />
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
class CellEditWithPromise extends Component {
|
||||
handleCellEditing = (rowId, dataField, newValue) => {
|
||||
return sleep(1000).then(() => {
|
||||
if (dataField === 'price' && (newValue < 2000 || isNaN(newValue))) {
|
||||
throw new Error('Product Price should bigger than $2000');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const cellEdit = {
|
||||
mode: 'click',
|
||||
blurToSave: true,
|
||||
onUpdate: this.handleCellEditing
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<BootstrapTable keyField="id" data={ products } columns={ columns } cellEdit={ cellEdit } />
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default CellEditWithPromise;
|
||||
|
||||
@ -1,212 +0,0 @@
|
||||
/* eslint no-unused-vars: 0 */
|
||||
/* eslint react/prop-types: 0 */
|
||||
/* eslint arrow-body-style: 0 */
|
||||
/* eslint consistent-return: 0 */
|
||||
/* eslint no-class-assign: 0 */
|
||||
import React, { Component } from 'react';
|
||||
import thunk from 'redux-thunk';
|
||||
import { Provider, connect } from 'react-redux';
|
||||
import { createStore, applyMiddleware } from 'redux';
|
||||
import BootstrapTable from 'react-bootstrap-table2';
|
||||
import Code from 'components/common/code-block';
|
||||
import { productsGenerator } from 'utils/common';
|
||||
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID'
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name'
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price'
|
||||
}];
|
||||
|
||||
const sourceCode = `\
|
||||
/////////////////////// Action Creator ///////////////////////
|
||||
const setErrorMessage = (errorMessage = null) => {
|
||||
return { type: 'SET_ERR_MESSAGE', errorMessage };
|
||||
};
|
||||
|
||||
// Async Action, using redux-thunk
|
||||
const cellEditingAsync = (rowId, dataField, newValue) => {
|
||||
return (dispatch) => {
|
||||
setTimeout(() => {
|
||||
if (dataField === 'price' && (newValue < 2000 || isNaN(newValue))) {
|
||||
dispatch(setErrorMessage('Product Price should bigger than $2000'));
|
||||
} else {
|
||||
dispatch({ type: 'ADD_SUCCESS', rowId, dataField, newValue });
|
||||
}
|
||||
}, 1200);
|
||||
};
|
||||
};
|
||||
|
||||
/////////////////////// Component ///////////////////////
|
||||
class CellEditWithRedux extends Component {
|
||||
// dispatch a async action
|
||||
handleCellEditing = (rowId, dataField, newValue) => {
|
||||
this.props.dispatch(cellEditingAsync(rowId, dataField, newValue));
|
||||
return false;
|
||||
}
|
||||
|
||||
handleErrorMsgDisappear = () => {
|
||||
this.props.dispatch(setErrorMessage());
|
||||
}
|
||||
|
||||
render() {
|
||||
const cellEdit = {
|
||||
mode: 'click',
|
||||
editing: this.props.cellEditing,
|
||||
errorMessage: this.props.errorMessage,
|
||||
onUpdate: this.handleCellEditing,
|
||||
onErrorMessageDisappear: this.handleErrorMsgDisappear
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<BootstrapTable keyField="id" data={ this.props.data } columns={ columns } cellEdit={ cellEdit } />
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
// connect
|
||||
CellEditWithRedux = connect(state => state)(CellEditWithRedux);
|
||||
|
||||
/////////////////////// Reducer ///////////////////////
|
||||
// initial state object and simple reducers
|
||||
const initialState = {
|
||||
data: productsGenerator(),
|
||||
cellEditing: false,
|
||||
errorMessage: null
|
||||
};
|
||||
|
||||
const reducers = (state, action) => {
|
||||
switch (action.type) {
|
||||
case 'ADD_SUCCESS': {
|
||||
const { rowId, dataField, newValue } = action;
|
||||
const data = [...state.data];
|
||||
const rowIndex = data.findIndex(r => r.id === rowId);
|
||||
data[rowIndex][dataField] = newValue;
|
||||
return {
|
||||
data,
|
||||
cellEditing: false,
|
||||
errorMessage: null
|
||||
};
|
||||
}
|
||||
case 'SET_ERR_MESSAGE': {
|
||||
const { errorMessage } = action;
|
||||
return {
|
||||
...state,
|
||||
cellEditing: true,
|
||||
errorMessage
|
||||
};
|
||||
}
|
||||
default: {
|
||||
return { ...state };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////// Index ///////////////////////
|
||||
const store = createStore(reducers, initialState, applyMiddleware(thunk));
|
||||
|
||||
const Index = () => (
|
||||
<Provider store={store}>
|
||||
<CellEditWithRedux />
|
||||
</Provider>
|
||||
);
|
||||
`;
|
||||
|
||||
const setErrorMessage = (errorMessage = null) => {
|
||||
return { type: 'SET_ERR_MESSAGE', errorMessage };
|
||||
};
|
||||
|
||||
// Async Action, using redux-thunk
|
||||
const cellEditingAsync = (rowId, dataField, newValue) => {
|
||||
return (dispatch) => {
|
||||
setTimeout(() => {
|
||||
if (dataField === 'price' && (newValue < 2000 || isNaN(newValue))) {
|
||||
dispatch(setErrorMessage('Product Price should bigger than $2000'));
|
||||
} else {
|
||||
dispatch({ type: 'ADD_SUCCESS', rowId, dataField, newValue });
|
||||
}
|
||||
}, 1200);
|
||||
};
|
||||
};
|
||||
|
||||
class CellEditWithRedux extends Component {
|
||||
// dispatch a async action
|
||||
handleCellEditing = (rowId, dataField, newValue) => {
|
||||
this.props.dispatch(cellEditingAsync(rowId, dataField, newValue));
|
||||
return false;
|
||||
}
|
||||
|
||||
handleErrorMsgDisappear = () => {
|
||||
this.props.dispatch(setErrorMessage());
|
||||
}
|
||||
|
||||
render() {
|
||||
const cellEdit = {
|
||||
mode: 'click',
|
||||
editing: this.props.cellEditing,
|
||||
errorMessage: this.props.errorMessage,
|
||||
onUpdate: this.handleCellEditing,
|
||||
onErrorMessageDisappear: this.handleErrorMsgDisappear
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<BootstrapTable keyField="id" data={ this.props.data } columns={ columns } cellEdit={ cellEdit } />
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
// connect
|
||||
CellEditWithRedux = connect(state => state)(CellEditWithRedux);
|
||||
|
||||
// initial state object and simple reducers
|
||||
const initialState = {
|
||||
data: productsGenerator(),
|
||||
cellEditing: false,
|
||||
errorMessage: null
|
||||
};
|
||||
|
||||
const reducers = (state, action) => {
|
||||
switch (action.type) {
|
||||
case 'ADD_SUCCESS': {
|
||||
const { rowId, dataField, newValue } = action;
|
||||
const data = JSON.parse(JSON.stringify(state.data));
|
||||
const rowIndex = data.findIndex(r => r.id === rowId);
|
||||
data[rowIndex][dataField] = newValue;
|
||||
return {
|
||||
data,
|
||||
cellEditing: false,
|
||||
errorMessage: null
|
||||
};
|
||||
}
|
||||
case 'SET_ERR_MESSAGE': {
|
||||
const { errorMessage } = action;
|
||||
return {
|
||||
...state,
|
||||
cellEditing: true,
|
||||
errorMessage
|
||||
};
|
||||
}
|
||||
default: {
|
||||
return { ...state };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const store = createStore(reducers, initialState, applyMiddleware(thunk));
|
||||
|
||||
const Index = () => (
|
||||
<Provider store={ store }>
|
||||
<CellEditWithRedux />
|
||||
</Provider>
|
||||
);
|
||||
|
||||
export default Index;
|
||||
|
||||
165
packages/react-bootstrap-table2-example/examples/remote/remote-celledit.js
vendored
Normal file
165
packages/react-bootstrap-table2-example/examples/remote/remote-celledit.js
vendored
Normal file
@ -0,0 +1,165 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import BootstrapTable 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'
|
||||
}];
|
||||
|
||||
const sourceCode = `\
|
||||
const RemoteCellEdit = (props) => {
|
||||
const cellEdit = {
|
||||
mode: 'click',
|
||||
errorMessage: props.errorMessage
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<BootstrapTable
|
||||
remote={ { cellEdit: true } }
|
||||
keyField="id"
|
||||
data={ props.data }
|
||||
columns={ columns }
|
||||
cellEdit={ cellEdit }
|
||||
onTableChange={ props.onTableChange }
|
||||
/>
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
RemoteCellEdit.propTypes = {
|
||||
data: PropTypes.array.isRequired,
|
||||
onTableChange: PropTypes.func.isRequired,
|
||||
errorMessage: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
class Container extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
data: products,
|
||||
errorMessage: null
|
||||
};
|
||||
}
|
||||
|
||||
handleTableChange = (type, { data, cellEdit: { rowId, dataField, newValue } }) => {
|
||||
setTimeout(() => {
|
||||
if (newValue === 'test' && dataField === 'name') {
|
||||
this.setState(() => ({
|
||||
data,
|
||||
errorMessage: 'Oops, product name shouldn't be "test"'
|
||||
}));
|
||||
} else {
|
||||
const result = data.map((row) => {
|
||||
if (row.id === rowId) {
|
||||
const newRow = { ...row };
|
||||
newRow[dataField] = newValue;
|
||||
return newRow;
|
||||
}
|
||||
return row;
|
||||
});
|
||||
this.setState(() => ({
|
||||
data: result,
|
||||
errorMessage: null
|
||||
}));
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<RemoteCellEdit
|
||||
data={ this.state.data }
|
||||
errorMessage={ this.state.errorMessage }
|
||||
onTableChange={ this.handleTableChange }
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
const RemoteCellEdit = (props) => {
|
||||
const cellEdit = {
|
||||
mode: 'click',
|
||||
errorMessage: props.errorMessage
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<BootstrapTable
|
||||
remote={ { cellEdit: true } }
|
||||
keyField="id"
|
||||
data={ props.data }
|
||||
columns={ columns }
|
||||
cellEdit={ cellEdit }
|
||||
onTableChange={ props.onTableChange }
|
||||
/>
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
RemoteCellEdit.propTypes = {
|
||||
data: PropTypes.array.isRequired,
|
||||
onTableChange: PropTypes.func.isRequired,
|
||||
errorMessage: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
class Container extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
data: products,
|
||||
errorMessage: null
|
||||
};
|
||||
}
|
||||
|
||||
handleTableChange = (type, { data, cellEdit: { rowId, dataField, newValue } }) => {
|
||||
setTimeout(() => {
|
||||
if (newValue === 'test' && dataField === 'name') {
|
||||
this.setState(() => ({
|
||||
data,
|
||||
errorMessage: 'Oops, product name shouldn\'t be "test"'
|
||||
}));
|
||||
} else {
|
||||
const result = data.map((row) => {
|
||||
if (row.id === rowId) {
|
||||
const newRow = { ...row };
|
||||
newRow[dataField] = newValue;
|
||||
return newRow;
|
||||
}
|
||||
return row;
|
||||
});
|
||||
this.setState(() => ({
|
||||
data: result,
|
||||
errorMessage: null
|
||||
}));
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<RemoteCellEdit
|
||||
data={ this.state.data }
|
||||
errorMessage={ this.state.errorMessage }
|
||||
onTableChange={ this.handleTableChange }
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Container;
|
||||
@ -63,8 +63,6 @@ import CellEditHooks from 'examples/cell-edit/cell-edit-hooks-table';
|
||||
import CellEditValidator from 'examples/cell-edit/cell-edit-validator-table';
|
||||
import CellEditStyleTable from 'examples/cell-edit/cell-edit-style-table';
|
||||
import CellEditClassTable from 'examples/cell-edit/cell-edit-class-table';
|
||||
import CellEditWithPromise from 'examples/cell-edit/cell-edit-with-promise-table';
|
||||
import CellEditWithRedux from 'examples/cell-edit/cell-edit-with-redux-table';
|
||||
|
||||
// work on row selection
|
||||
import SingleSelectionTable from 'examples/row-selection/single-selection';
|
||||
@ -91,6 +89,7 @@ import TableOverlay from 'examples/loading-overlay/table-overlay';
|
||||
import RemoteSort from 'examples/remote/remote-sort';
|
||||
import RemoteFilter from 'examples/remote/remote-filter';
|
||||
import RemotePaginationTable from 'examples/remote/remote-pagination';
|
||||
import RemoteCellEdit from 'examples/remote/remote-celledit';
|
||||
import RemoteAll from 'examples/remote/remote-all';
|
||||
|
||||
// css style
|
||||
@ -165,9 +164,7 @@ storiesOf('Cell Editing', module)
|
||||
.add('Rich Hook Functions', () => <CellEditHooks />)
|
||||
.add('Validation', () => <CellEditValidator />)
|
||||
.add('Custom Cell Style When Editing', () => <CellEditStyleTable />)
|
||||
.add('Custom Cell Classes When Editing', () => <CellEditClassTable />)
|
||||
.add('Async Cell Editing(Promise)', () => <CellEditWithPromise />)
|
||||
.add('Async Cell Editing(Redux)', () => <CellEditWithRedux />);
|
||||
.add('Custom Cell Classes When Editing', () => <CellEditClassTable />);
|
||||
|
||||
storiesOf('Row Selection', module)
|
||||
.add('Single Selection', () => <SingleSelectionTable />)
|
||||
@ -194,4 +191,5 @@ storiesOf('Remote', module)
|
||||
.add('Remote Sort', () => <RemoteSort />)
|
||||
.add('Remote Filter', () => <RemoteFilter />)
|
||||
.add('Remote Pagination', () => <RemotePaginationTable />)
|
||||
.add('Remote Cell Editing', () => <RemoteCellEdit />)
|
||||
.add('Remote All', () => <RemoteAll />);
|
||||
|
||||
@ -28,7 +28,7 @@ describe('Wrapper', () => {
|
||||
onTableChangeCB.reset();
|
||||
});
|
||||
|
||||
const createTableProps = () => {
|
||||
const createTableProps = (props) => {
|
||||
const tableProps = {
|
||||
keyField: 'id',
|
||||
columns: [{
|
||||
@ -47,7 +47,8 @@ describe('Wrapper', () => {
|
||||
filter: filter(),
|
||||
_,
|
||||
store: new Store('id'),
|
||||
onTableChange: onTableChangeCB
|
||||
onTableChange: onTableChangeCB,
|
||||
...props
|
||||
};
|
||||
tableProps.store.data = data;
|
||||
return tableProps;
|
||||
@ -105,6 +106,17 @@ describe('Wrapper', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('when props.isDataChanged is true and remote is enable', () => {
|
||||
beforeEach(() => {
|
||||
nextProps = createTableProps({ isDataChanged: true });
|
||||
instance.componentWillReceiveProps(nextProps);
|
||||
});
|
||||
|
||||
it('should setting isDataChanged as true', () => {
|
||||
expect(instance.state.isDataChanged).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when props.store.filters is different from current state.currFilters', () => {
|
||||
beforeEach(() => {
|
||||
nextProps = createTableProps();
|
||||
|
||||
@ -31,13 +31,10 @@ describe('CellEditWrapper', () => {
|
||||
};
|
||||
|
||||
const keyField = 'id';
|
||||
let onUpdateCellCB = sinon.stub();
|
||||
const store = new Store(keyField);
|
||||
store.data = data;
|
||||
|
||||
const CellEditWrapper = wrapperFactory(Container, {
|
||||
onUpdateCell: onUpdateCellCB
|
||||
});
|
||||
const CellEditWrapper = wrapperFactory(Container);
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(
|
||||
@ -60,24 +57,24 @@ describe('CellEditWrapper', () => {
|
||||
expect(wrapper.state().ridx).toBeNull();
|
||||
expect(wrapper.state().cidx).toBeNull();
|
||||
expect(wrapper.state().message).toBeNull();
|
||||
expect(wrapper.state().editing).toBeFalsy();
|
||||
expect(wrapper.state().isDataChanged).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should inject correct props to base component', () => {
|
||||
expect(wrapper.props().onCellUpdate).toBeDefined();
|
||||
expect(wrapper.props().onStartEditing).toBeDefined();
|
||||
expect(wrapper.props().onEscapeEditing).toBeDefined();
|
||||
expect(wrapper.props().isDataChanged).toBe(wrapper.state().isDataChanged);
|
||||
expect(wrapper.props().currEditCell).toBeDefined();
|
||||
expect(wrapper.props().currEditCell.ridx).toBeNull();
|
||||
expect(wrapper.props().currEditCell.cidx).toBeNull();
|
||||
expect(wrapper.props().currEditCell.message).toBeNull();
|
||||
expect(wrapper.props().currEditCell.editing).toBeFalsy();
|
||||
});
|
||||
|
||||
describe('when receive new cellEdit prop', () => {
|
||||
const spy = jest.spyOn(CellEditWrapper.prototype, 'escapeEditing');
|
||||
|
||||
describe('and cellEdit.editing is false', () => {
|
||||
describe('and cellEdit is not work on remote', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(
|
||||
<CellEditWrapper
|
||||
@ -88,54 +85,69 @@ describe('CellEditWrapper', () => {
|
||||
store={ store }
|
||||
/>
|
||||
);
|
||||
wrapper.setProps({ cellEdit: { ...cellEdit, editing: false } });
|
||||
wrapper.setProps({ cellEdit: { ...cellEdit } });
|
||||
});
|
||||
|
||||
it('should call escapeEditing', () => {
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should have correct state', () => {
|
||||
expect(wrapper.state().ridx).toBeNull();
|
||||
expect(wrapper.state().cidx).toBeNull();
|
||||
expect(wrapper.state().message).toBeNull();
|
||||
expect(wrapper.state().editing).toBeFalsy();
|
||||
it('should always setting state.isDataChanged as false', () => {
|
||||
expect(wrapper.state().isDataChanged).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('and cellEdit.editing is true', () => {
|
||||
const errorMessage = 'test';
|
||||
describe('and cellEdit is work on remote', () => {
|
||||
let errorMessage;
|
||||
const ridx = 1;
|
||||
const cidx = 2;
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(
|
||||
<CellEditWrapper
|
||||
keyField={ keyField }
|
||||
data={ data }
|
||||
columns={ columns }
|
||||
cellEdit={ cellEdit }
|
||||
store={ store }
|
||||
/>
|
||||
);
|
||||
wrapper.setState({ ridx, cidx, editing: true });
|
||||
wrapper.setProps({ cellEdit: { ...cellEdit, editing: true, errorMessage } });
|
||||
describe('and cellEdit.errorMessage is defined', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(
|
||||
<CellEditWrapper
|
||||
remote={ { cellEdit: true } }
|
||||
keyField={ keyField }
|
||||
data={ data }
|
||||
columns={ columns }
|
||||
cellEdit={ cellEdit }
|
||||
store={ store }
|
||||
/>
|
||||
);
|
||||
errorMessage = 'test';
|
||||
wrapper.setState({ ridx, cidx });
|
||||
wrapper.setProps({ cellEdit: { ...cellEdit, errorMessage } });
|
||||
});
|
||||
|
||||
it('should setting correct state', () => {
|
||||
expect(wrapper.state().ridx).toEqual(ridx);
|
||||
expect(wrapper.state().cidx).toEqual(cidx);
|
||||
expect(wrapper.state().isDataChanged).toBeFalsy();
|
||||
expect(wrapper.state().message).toEqual(errorMessage);
|
||||
});
|
||||
});
|
||||
|
||||
it('should have correct state', () => {
|
||||
expect(wrapper.state().ridx).toEqual(ridx);
|
||||
expect(wrapper.state().cidx).toEqual(cidx);
|
||||
expect(wrapper.state().editing).toBeTruthy();
|
||||
expect(wrapper.state().message).toEqual(errorMessage);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('and cellEdit.errorMessage is undefined', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(
|
||||
<CellEditWrapper
|
||||
remote={ { cellEdit: true } }
|
||||
keyField={ keyField }
|
||||
data={ data }
|
||||
columns={ columns }
|
||||
cellEdit={ cellEdit }
|
||||
store={ store }
|
||||
/>
|
||||
);
|
||||
errorMessage = null;
|
||||
wrapper.setState({ ridx, cidx });
|
||||
wrapper.setProps({ cellEdit: { ...cellEdit, errorMessage } });
|
||||
});
|
||||
|
||||
describe('call updateEditingWithErr function', () => {
|
||||
it('should set state.message correctly', () => {
|
||||
const message = 'test';
|
||||
wrapper.instance().updateEditingWithErr(message);
|
||||
expect(wrapper.state().message).toEqual(message);
|
||||
it('should setting correct state', () => {
|
||||
expect(wrapper.state().isDataChanged).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should escape current editing', () => {
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -144,7 +156,6 @@ describe('CellEditWrapper', () => {
|
||||
wrapper.instance().escapeEditing();
|
||||
expect(wrapper.state().ridx).toBeNull();
|
||||
expect(wrapper.state().cidx).toBeNull();
|
||||
expect(wrapper.state().editing).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
@ -155,7 +166,7 @@ describe('CellEditWrapper', () => {
|
||||
wrapper.instance().startEditing(ridx, cidx);
|
||||
expect(wrapper.state().ridx).toEqual(ridx);
|
||||
expect(wrapper.state().cidx).toEqual(cidx);
|
||||
expect(wrapper.state().editing).toBeTruthy();
|
||||
expect(wrapper.state().isDataChanged).toBeFalsy();
|
||||
});
|
||||
|
||||
describe('if selectRow.clickToSelect is defined', () => {
|
||||
@ -199,7 +210,6 @@ describe('CellEditWrapper', () => {
|
||||
wrapper.instance().startEditing(ridx, cidx);
|
||||
expect(wrapper.state().ridx).toEqual(ridx);
|
||||
expect(wrapper.state().cidx).toEqual(cidx);
|
||||
expect(wrapper.state().editing).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -210,7 +220,7 @@ describe('CellEditWrapper', () => {
|
||||
expect(wrapper.state().ridx).toBeNull();
|
||||
expect(wrapper.state().cidx).toBeNull();
|
||||
expect(wrapper.state().message).toBeNull();
|
||||
expect(wrapper.state().editing).toBeFalsy();
|
||||
expect(wrapper.state().isDataChanged).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@ -219,35 +229,75 @@ describe('CellEditWrapper', () => {
|
||||
const column = columns[1];
|
||||
const newValue = 'new name';
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(
|
||||
<CellEditWrapper
|
||||
keyField={ keyField }
|
||||
data={ data }
|
||||
columns={ columns }
|
||||
cellEdit={ cellEdit }
|
||||
store={ store }
|
||||
/>
|
||||
);
|
||||
wrapper.instance().handleCellUpdate(row, column, newValue);
|
||||
describe('when cell edit is work on remote', () => {
|
||||
const spy = jest.spyOn(CellEditWrapper.prototype, 'handleCellChange');
|
||||
const onTableChangeCB = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(
|
||||
<CellEditWrapper
|
||||
remote={ { cellEdit: true } }
|
||||
keyField={ keyField }
|
||||
data={ data }
|
||||
columns={ columns }
|
||||
cellEdit={ cellEdit }
|
||||
onTableChange={ onTableChangeCB }
|
||||
store={ store }
|
||||
/>
|
||||
);
|
||||
wrapper.instance().handleCellUpdate(row, column, newValue);
|
||||
});
|
||||
|
||||
it('should calling handleCellChange correctly', () => {
|
||||
expect(spy).toHaveBeenCalled();
|
||||
expect(spy.mock.calls).toHaveLength(1);
|
||||
expect(spy.mock.calls[0]).toHaveLength(3);
|
||||
expect(spy.mock.calls[0][0]).toEqual(row[keyField]);
|
||||
expect(spy.mock.calls[0][1]).toEqual(column.dataField);
|
||||
expect(spy.mock.calls[0][2]).toEqual(newValue);
|
||||
});
|
||||
});
|
||||
|
||||
it('should calling onUpdateCell callback correctly', () => {
|
||||
expect(onUpdateCellCB.callCount).toBe(1);
|
||||
expect(onUpdateCellCB.calledWith(row.id, column.dataField, newValue)).toBe(true);
|
||||
});
|
||||
describe('when cell edit is not work on remote', () => {
|
||||
const spyOnCompleteEditing = jest.spyOn(CellEditWrapper.prototype, 'completeEditing');
|
||||
const spyOnStoreEdit = jest.spyOn(Store.prototype, 'edit');
|
||||
|
||||
describe('when onUpdateCell function return true', () => {
|
||||
const spy = jest.spyOn(CellEditWrapper.prototype, 'completeEditing');
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(
|
||||
<CellEditWrapper
|
||||
keyField={ keyField }
|
||||
data={ data }
|
||||
columns={ columns }
|
||||
cellEdit={ cellEdit }
|
||||
store={ store }
|
||||
/>
|
||||
);
|
||||
wrapper.instance().handleCellUpdate(row, column, newValue);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
spyOnStoreEdit.mockReset();
|
||||
spyOnCompleteEditing.mockReset();
|
||||
});
|
||||
|
||||
it('should calling props.store.edit', () => {
|
||||
expect(spyOnStoreEdit).toHaveBeenCalled();
|
||||
expect(spyOnStoreEdit.mock.calls).toHaveLength(1);
|
||||
expect(spyOnStoreEdit.mock.calls[0]).toHaveLength(3);
|
||||
expect(spyOnStoreEdit.mock.calls[0][0]).toEqual(row[keyField]);
|
||||
expect(spyOnStoreEdit.mock.calls[0][1]).toEqual(column.dataField);
|
||||
expect(spyOnStoreEdit.mock.calls[0][2]).toEqual(newValue);
|
||||
});
|
||||
|
||||
it('should calling completeEditing function', () => {
|
||||
expect(spy).toHaveBeenCalled();
|
||||
expect(spyOnCompleteEditing).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('if cellEdit.afterSaveCell prop defined', () => {
|
||||
const aftereSaveCellCallBack = sinon.stub();
|
||||
|
||||
beforeEach(() => {
|
||||
cellEdit.beforeSaveCell = aftereSaveCellCallBack;
|
||||
cellEdit.afterSaveCell = aftereSaveCellCallBack;
|
||||
wrapper = shallow(
|
||||
<CellEditWrapper
|
||||
keyField={ keyField }
|
||||
@ -269,28 +319,6 @@ describe('CellEditWrapper', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('when onUpdateCell function return false', () => {
|
||||
const spy = jest.spyOn(CellEditWrapper.prototype, 'completeEditing');
|
||||
|
||||
beforeEach(() => {
|
||||
onUpdateCellCB = sinon.stub().returns(false);
|
||||
wrapper = shallow(
|
||||
<CellEditWrapper
|
||||
keyField={ keyField }
|
||||
data={ data }
|
||||
columns={ columns }
|
||||
cellEdit={ cellEdit }
|
||||
store={ store }
|
||||
/>
|
||||
);
|
||||
wrapper.instance().handleCellUpdate(row, column, newValue);
|
||||
});
|
||||
|
||||
it('shouldn\'t calling completeEditing function', () => {
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('if cellEdit.beforeSaveCell prop defined', () => {
|
||||
const beforeSaveCellCallBack = sinon.stub();
|
||||
beforeEach(() => {
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
/* eslint react/prefer-stateless-function: 0 */
|
||||
/* eslint react/no-multi-comp: 0 */
|
||||
import React from 'react';
|
||||
import sinon from 'sinon';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import BootstrapTable from '../src/bootstrap-table';
|
||||
import Container from '../src';
|
||||
import { getRowByRowId } from '../src/store/rows';
|
||||
|
||||
describe('container', () => {
|
||||
let wrapper;
|
||||
@ -79,63 +77,6 @@ describe('container', () => {
|
||||
it('should render BootstrapTable component successfully', () => {
|
||||
expect(wrapper.dive().find(BootstrapTable)).toHaveLength(1);
|
||||
});
|
||||
|
||||
describe('for handleUpdateCell function', () => {
|
||||
const rowId = data[1].id;
|
||||
const dataField = columns[1].dataField;
|
||||
const newValue = 'tester';
|
||||
let result;
|
||||
|
||||
describe('when cellEdit.onUpdate callback is not defined', () => {
|
||||
beforeEach(() => {
|
||||
result = wrapper.instance().handleUpdateCell(rowId, dataField, newValue);
|
||||
});
|
||||
|
||||
it('should return true', () => {
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should update store data directly', () => {
|
||||
const store = wrapper.instance().store;
|
||||
const row = getRowByRowId(store)(rowId);
|
||||
expect(row[dataField]).toEqual(newValue);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when cellEdit.onUpdate callback is define and which return false', () => {
|
||||
beforeEach(() => {
|
||||
cellEdit.onUpdate = sinon.stub().returns(false);
|
||||
wrapper = shallow(
|
||||
<Container
|
||||
keyField={ keyField }
|
||||
data={ data }
|
||||
columns={ columns }
|
||||
cellEdit={ cellEdit }
|
||||
/>
|
||||
);
|
||||
result = wrapper.instance().handleUpdateCell(rowId, dataField, newValue);
|
||||
});
|
||||
|
||||
it('should calling cellEdit.onUpdate callback correctly', () => {
|
||||
expect(cellEdit.onUpdate.callCount).toBe(1);
|
||||
expect(cellEdit.onUpdate.calledWith(rowId, dataField, newValue)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false', () => {
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
|
||||
it('shouldn\'t update store data', () => {
|
||||
const store = wrapper.instance().store;
|
||||
const row = getRowByRowId(store)(rowId);
|
||||
expect(row[dataField]).not.toEqual(newValue);
|
||||
});
|
||||
});
|
||||
|
||||
// We need refactoring handleUpdateCell function for handling promise firstly
|
||||
// then it will be much easier to test
|
||||
describe.skip('when cellEdit.onUpdate callback is define and which return a Promise', () => {});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when selectRow prop is defined', () => {
|
||||
|
||||
@ -93,7 +93,6 @@ describe('TableResolver', () => {
|
||||
const expectNonEditableRows = [1, 2];
|
||||
const cellEdit = {
|
||||
mode: Const.DBCLICK_TO_CELL_EDIT,
|
||||
onUpdate: sinon.stub(),
|
||||
blurToSave: true,
|
||||
beforeSaveCell: sinon.stub(),
|
||||
afterSaveCell: sinon.stub(),
|
||||
|
||||
@ -134,6 +134,58 @@ describe('remoteResolver', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('isRemoteCellEdit', () => {
|
||||
describe('when remote is false', () => {
|
||||
beforeEach(() => {
|
||||
shallowContainer();
|
||||
});
|
||||
|
||||
it('should return false', () => {
|
||||
expect(wrapper.instance().isRemoteCellEdit()).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when remote is true', () => {
|
||||
beforeEach(() => {
|
||||
shallowContainer({ remote: true });
|
||||
});
|
||||
|
||||
it('should return true', () => {
|
||||
expect(wrapper.instance().isRemoteCellEdit()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when remote.cellEdit is true', () => {
|
||||
beforeEach(() => {
|
||||
shallowContainer({ remote: { cellEdit: true } });
|
||||
});
|
||||
|
||||
it('should return true', () => {
|
||||
expect(wrapper.instance().isRemoteCellEdit()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleCellChange', () => {
|
||||
const onTableChangeCB = sinon.stub();
|
||||
const rowId = 1;
|
||||
const dataField = 'name';
|
||||
const newValue = 'test';
|
||||
|
||||
beforeEach(() => {
|
||||
onTableChangeCB.reset();
|
||||
shallowContainer({ onTableChange: onTableChangeCB });
|
||||
wrapper.instance().handleCellChange(rowId, dataField, newValue);
|
||||
});
|
||||
|
||||
it('should calling props.onTableChange correctly', () => {
|
||||
const cellEdit = { rowId, dataField, newValue };
|
||||
expect(onTableChangeCB.calledOnce).toBeTruthy();
|
||||
expect(onTableChangeCB.calledWith(
|
||||
'cellEdit', wrapper.instance().getNewestState({ cellEdit }))).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleSortChange', () => {
|
||||
const onTableChangeCB = sinon.stub();
|
||||
beforeEach(() => {
|
||||
|
||||
@ -273,7 +273,6 @@ describe('Row', () => {
|
||||
cellEdit.cidx = editingColIndex;
|
||||
cellEdit.onUpdate = sinon.stub();
|
||||
cellEdit.onEscape = sinon.stub();
|
||||
cellEdit.onUpdate = sinon.stub();
|
||||
wrapper = shallow(
|
||||
<Row
|
||||
{ ...mockBodyResolvedProps }
|
||||
|
||||
Loading…
Reference in New Issue
Block a user