diff --git a/package.json b/package.json index ae5416b..4437f6e 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "css-loader": "0.28.1", "enzyme": "3.3.0", "enzyme-adapter-react-16": "1.1.1", + "enzyme-to-json": "3.3.4", "eslint": "4.5.0", "eslint-config-airbnb": "15.1.0", "eslint-loader": "1.9.0", diff --git a/packages/react-bootstrap-table2-example/examples/loading-overlay/empty-table-overlay.js b/packages/react-bootstrap-table2-example/examples/loading-overlay/empty-table-overlay.js index faa0261..6dadff3 100644 --- a/packages/react-bootstrap-table2-example/examples/loading-overlay/empty-table-overlay.js +++ b/packages/react-bootstrap-table2-example/examples/loading-overlay/empty-table-overlay.js @@ -22,8 +22,19 @@ const columns = [{ const sourceCode = `\ import BootstrapTable from 'react-bootstrap-table-next'; import paginationFactory from 'react-bootstrap-table2-paginator'; + // ... -const RemotePagination = ({ data, page, sizePerPage, onTableChange, totalSize }) => ( +const NoDataIndication = () => ( +
+
+
+
+
+
+
+); + +const Table = ({ data, page, sizePerPage, onTableChange, totalSize }) => (
} /> { sourceCode }
); -class Container extends React.Component { +class EmptyTableOverlay extends React.Component { constructor(props) { super(props); this.state = { @@ -47,7 +59,7 @@ class Container extends React.Component { }; } - handleTableChange = ({ page, sizePerPage }) => { + handleTableChange = (type, { page, sizePerPage }) => { const currentIndex = (page - 1) * sizePerPage; setTimeout(() => { this.setState(() => ({ @@ -55,13 +67,14 @@ class Container extends React.Component { data: products.slice(currentIndex, currentIndex + sizePerPage), sizePerPage })); - }, 2000); + }, 3000); + this.setState(() => ({ data: [] })); } render() { const { data, sizePerPage, page } = this.state; return ( - { - const end = endIndex(page, sizePerPage, pageStartIndex); const dataSize = data.length; - if (end - 1 > dataSize) { + if (page < pageStartIndex || page > (Math.floor(dataSize / sizePerPage) + pageStartIndex)) { return pageStartIndex; } return page; diff --git a/packages/react-bootstrap-table2-paginator/test/context.test.js b/packages/react-bootstrap-table2-paginator/test/context.test.js index 4b9c30d..9d13658 100644 --- a/packages/react-bootstrap-table2-paginator/test/context.test.js +++ b/packages/react-bootstrap-table2-paginator/test/context.test.js @@ -126,69 +126,6 @@ describe('PaginationContext', () => { let instance; let nextProps; - describe('when nextProps.pagination.options.page is existing', () => { - const onPageChange = jest.fn(); - afterEach(() => { - onPageChange.mockReset(); - }); - - describe('and if it is different with currPage', () => { - beforeEach(() => { - wrapper = shallow(shallowContext()); - instance = wrapper.instance(); - wrapper.render(); - nextProps = { - data, - pagination: { - options: { - page: 2, - onPageChange - } - } - }; - instance.componentWillReceiveProps(nextProps); - }); - - it('should call options.onPageChange', () => { - expect(onPageChange).toHaveBeenCalledTimes(1); - expect(onPageChange).toHaveBeenCalledWith( - instance.currPage, - instance.currSizePerPage - ); - }); - - it('should set correct currPage', () => { - expect(instance.currPage).toEqual(nextProps.pagination.options.page); - }); - }); - - describe('and if it is same as currPage', () => { - beforeEach(() => { - wrapper = shallow(shallowContext()); - instance = wrapper.instance(); - wrapper.render(); - nextProps = { - data, - pagination: { - options: { - page: 1, - onPageChange - } - } - }; - instance.componentWillReceiveProps(nextProps); - }); - - it('shouldn\'t call options.onPageChange', () => { - expect(onPageChange).toHaveBeenCalledTimes(0); - }); - - it('should have correct currPage', () => { - expect(instance.currPage).toEqual(nextProps.pagination.options.page); - }); - }); - }); - describe('when nextProps.pagination.options.page is not existing', () => { beforeEach(() => { wrapper = shallow(shallowContext({ @@ -206,69 +143,6 @@ describe('PaginationContext', () => { }); }); - describe('when nextProps.pagination.options.sizePerPage is existing', () => { - const onPageChange = jest.fn(); - afterEach(() => { - onPageChange.mockReset(); - }); - - describe('and if it is different with currSizePerPage', () => { - beforeEach(() => { - wrapper = shallow(shallowContext()); - instance = wrapper.instance(); - wrapper.render(); - nextProps = { - data, - pagination: { - options: { - sizePerPage: Const.SIZE_PER_PAGE_LIST[2], - onPageChange - } - } - }; - instance.componentWillReceiveProps(nextProps); - }); - - it('should call options.onPageChange', () => { - expect(onPageChange).toHaveBeenCalledTimes(1); - expect(onPageChange).toHaveBeenCalledWith( - instance.currPage, - instance.currSizePerPage - ); - }); - - it('should set correct currSizePerPage', () => { - expect(instance.currSizePerPage).toEqual(nextProps.pagination.options.sizePerPage); - }); - }); - - describe('and if it is same as currSizePerPage', () => { - beforeEach(() => { - wrapper = shallow(shallowContext()); - instance = wrapper.instance(); - wrapper.render(); - nextProps = { - data, - pagination: { - options: { - sizePerPage: Const.SIZE_PER_PAGE_LIST[0], - onPageChange - } - } - }; - instance.componentWillReceiveProps(nextProps); - }); - - it('shouldn\'t call options.onPageChange', () => { - expect(onPageChange).toHaveBeenCalledTimes(0); - }); - - it('should have correct currSizePerPage', () => { - expect(instance.currSizePerPage).toEqual(nextProps.pagination.options.sizePerPage); - }); - }); - }); - describe('when nextProps.pagination.options.sizePerPage is not existing', () => { beforeEach(() => { wrapper = shallow(shallowContext({ @@ -281,10 +155,53 @@ describe('PaginationContext', () => { instance.componentWillReceiveProps(nextProps); }); - it('should not set currPage', () => { + it('should not set currSizePerPage', () => { expect(instance.currSizePerPage).toEqual(Const.SIZE_PER_PAGE_LIST[2]); }); }); + + describe('when page is not align', () => { + beforeEach(() => { + wrapper = shallow(shallowContext({ + ...defaultPagination, + page: 2 + })); + instance = wrapper.instance(); + wrapper.render(); + nextProps = { + data: [], + pagination: { ...defaultPagination } + }; + instance.componentWillReceiveProps(nextProps); + }); + + it('should reset currPage to first page', () => { + expect(instance.currPage).toEqual(1); + }); + + describe('if options.onPageChange is defined', () => { + const onPageChange = jest.fn(); + beforeEach(() => { + onPageChange.mockClear(); + wrapper = shallow(shallowContext({ + ...defaultPagination, + page: 2 + })); + instance = wrapper.instance(); + wrapper.render(); + nextProps = { + data: [], + pagination: { ...defaultPagination, options: { onPageChange } } + }; + instance.componentWillReceiveProps(nextProps); + }); + + it('should call options.onPageChange correctly', () => { + expect(onPageChange).toHaveBeenCalledTimes(1); + expect(onPageChange).toHaveBeenCalledWith(instance.currPage, instance.currSizePerPage); + }); + }); + }); }); describe('handleChangePage', () => { diff --git a/packages/react-bootstrap-table2-paginator/test/page.test.js b/packages/react-bootstrap-table2-paginator/test/page.test.js index 28ab1e1..dad8742 100644 --- a/packages/react-bootstrap-table2-paginator/test/page.test.js +++ b/packages/react-bootstrap-table2-paginator/test/page.test.js @@ -45,8 +45,8 @@ describe('Page Functions', () => { describe('alignPage', () => { const pageStartIndex = 1; const sizePerPage = 10; - const page = 2; - describe('if the length of store.data is less than the end page index', () => { + const page = 3; + describe('if the page does not fit the pages interval calculated from the length of store.data', () => { beforeEach(() => { data = []; for (let i = 0; i < 15; i += 1) { diff --git a/packages/react-bootstrap-table2-toolkit/src/search/context.js b/packages/react-bootstrap-table2-toolkit/src/search/context.js index 67935bf..c579999 100644 --- a/packages/react-bootstrap-table2-toolkit/src/search/context.js +++ b/packages/react-bootstrap-table2-toolkit/src/search/context.js @@ -20,11 +20,26 @@ export default (options = { searchText: PropTypes.string } + constructor(props) { + super(props); + this.performRemoteSearch = props.searchText !== ''; + } + + componentWillReceiveProps(nextProps) { + if (isRemoteSearch()) { + if (nextProps.searchText !== this.props.searchText) { + this.performRemoteSearch = true; + } else { + this.performRemoteSearch = false; + } + } + } + search() { const { data, columns } = this.props; let { searchText } = this.props; - if (isRemoteSearch()) { + if (isRemoteSearch() && this.performRemoteSearch) { handleRemoteSearchChange(searchText); return data; } diff --git a/packages/react-bootstrap-table2/src/row-selection/selection-cell.js b/packages/react-bootstrap-table2/src/row-selection/selection-cell.js index e7571a2..cdd6bbd 100644 --- a/packages/react-bootstrap-table2/src/row-selection/selection-cell.js +++ b/packages/react-bootstrap-table2/src/row-selection/selection-cell.js @@ -75,6 +75,7 @@ export default class SelectionCell extends Component { checked={ selected } disabled={ disabled } className={ bootstrap4 ? 'selection-input-4' : '' } + onChange={ () => {} } /> ) } diff --git a/packages/react-bootstrap-table2/src/row-selection/selection-header-cell.js b/packages/react-bootstrap-table2/src/row-selection/selection-header-cell.js index 169740f..3658e0a 100644 --- a/packages/react-bootstrap-table2/src/row-selection/selection-header-cell.js +++ b/packages/react-bootstrap-table2/src/row-selection/selection-header-cell.js @@ -12,6 +12,7 @@ export const CheckBox = ({ className, checked, indeterminate }) => ( ref={ (input) => { if (input) input.indeterminate = indeterminate; // eslint-disable-line no-param-reassign } } + onChange={ () => {} } /> ); diff --git a/packages/react-bootstrap-table2/test/row-selection/__snapshots__/selection-cell.test.js.snap b/packages/react-bootstrap-table2/test/row-selection/__snapshots__/selection-cell.test.js.snap new file mode 100644 index 0000000..2f5e4dc --- /dev/null +++ b/packages/react-bootstrap-table2/test/row-selection/__snapshots__/selection-cell.test.js.snap @@ -0,0 +1,14 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` render should render component correctly 1`] = ` + + + +`; diff --git a/packages/react-bootstrap-table2/test/row-selection/__snapshots__/selection-header-cell.test.js.snap b/packages/react-bootstrap-table2/test/row-selection/__snapshots__/selection-header-cell.test.js.snap new file mode 100644 index 0000000..522b3e5 --- /dev/null +++ b/packages/react-bootstrap-table2/test/row-selection/__snapshots__/selection-header-cell.test.js.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` render should render component correctly 1`] = ` + +`; diff --git a/packages/react-bootstrap-table2/test/row-selection/selection-cell.test.js b/packages/react-bootstrap-table2/test/row-selection/selection-cell.test.js index d3c9eac..311c361 100644 --- a/packages/react-bootstrap-table2/test/row-selection/selection-cell.test.js +++ b/packages/react-bootstrap-table2/test/row-selection/selection-cell.test.js @@ -1,6 +1,7 @@ import 'jsdom-global/register'; import React from 'react'; import { shallow } from 'enzyme'; +import toJson from 'enzyme-to-json'; import sinon from 'sinon'; import { shallowWithContext } from '../test-helpers/new-context'; @@ -61,7 +62,8 @@ describe('', () => { mode={ mode } rowIndex={ rowIndex } onRowSelect={ mockOnRowSelect } - />, { bootstrap4: false } + />, + { bootstrap4: false } ); wrapper.find('td').simulate('click'); }); @@ -72,9 +74,7 @@ describe('', () => { it('should calling onRowSelect callback correctly', () => { expect(mockOnRowSelect.calledOnce).toBe(true); - expect( - mockOnRowSelect.calledWith(rowKey, !selected, rowIndex) - ).toBe(true); + expect(mockOnRowSelect.calledWith(rowKey, !selected, rowIndex)).toBe(true); }); }); @@ -88,7 +88,8 @@ describe('', () => { rowIndex={ rowIndex } onRowSelect={ mockOnRowSelect } disabled - />, { bootstrap4: false } + />, + { bootstrap4: false } ); wrapper.find('td').simulate('click'); }); @@ -111,7 +112,8 @@ describe('', () => { mode="radio" rowIndex={ rowIndex } onRowSelect={ mockOnRowSelect } - />, { bootstrap4: false } + />, + { bootstrap4: false } ); }); @@ -132,11 +134,12 @@ describe('', () => { rowIndex={ rowIndex } selected onRowSelect={ mockOnRowSelect } - />, { bootstrap4: false } + />, + { bootstrap4: false } ); }); - it('should be called with correct paramters', () => { + it('should be called with correct parameters', () => { // first click wrapper.find('td').simulate('click'); expect(mockOnRowSelect.callCount).toBe(1); @@ -151,12 +154,8 @@ describe('', () => { beforeEach(() => { wrapper = shallowWithContext( - , { bootstrap4: false } + , + { bootstrap4: false } ); }); @@ -165,6 +164,7 @@ describe('', () => { expect(wrapper.find('input')).toHaveLength(1); expect(wrapper.find('input').get(0).props.type).toBe(mode); expect(wrapper.find('input').get(0).props.checked).toBe(selected); + expect(toJson(wrapper)).toMatchSnapshot(); }); describe('when disabled prop give as true', () => { @@ -176,7 +176,8 @@ describe('', () => { rowIndex={ rowIndex } selected={ selected } disabled - />, { bootstrap4: false } + />, + { bootstrap4: false } ); }); @@ -198,7 +199,8 @@ describe('', () => { rowIndex={ rowIndex } selected={ selected } selectionRenderer={ selectionRenderer } - />, { bootstrap4: false } + />, + { bootstrap4: false } ); }); @@ -219,12 +221,8 @@ describe('', () => { describe('when bootstrap4 context is true', () => { beforeEach(() => { wrapper = shallowWithContext( - , { bootstrap4: true } + , + { bootstrap4: true } ); }); diff --git a/packages/react-bootstrap-table2/test/row-selection/selection-header-cell.test.js b/packages/react-bootstrap-table2/test/row-selection/selection-header-cell.test.js index 4423dbf..be9a519 100644 --- a/packages/react-bootstrap-table2/test/row-selection/selection-header-cell.test.js +++ b/packages/react-bootstrap-table2/test/row-selection/selection-header-cell.test.js @@ -1,5 +1,6 @@ import React from 'react'; import { shallow } from 'enzyme'; +import toJson from 'enzyme-to-json'; import sinon from 'sinon'; import { shallowWithContext } from '../test-helpers/new-context'; @@ -201,6 +202,7 @@ describe('', () => { expect(wrapper.find('input').length).toBe(1); expect(wrapper.find('input').prop('checked')).toBe(checked); expect(wrapper.find('input').prop('type')).toBe('checkbox'); + expect(toJson(wrapper)).toMatchSnapshot(); }); }); }); diff --git a/yarn.lock b/yarn.lock index 4329d62..b44934f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2711,6 +2711,12 @@ enzyme-adapter-utils@^1.3.0: object.assign "^4.1.0" prop-types "^15.6.0" +enzyme-to-json@3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/enzyme-to-json/-/enzyme-to-json-3.3.4.tgz#67c6040e931182f183418af2eb9f4323258aa77f" + dependencies: + lodash "^4.17.4" + enzyme@3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.3.0.tgz#0971abd167f2d4bf3f5bd508229e1c4b6dc50479"