react-virtualized
Version:
React components for efficiently rendering large, scrollable lists and tabular data
1,201 lines (1,188 loc) • 102 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var React = _interopRequireWildcard(require("react"));
var _reactDom = require("react-dom");
var _testUtils = require("react-dom/test-utils");
var _reactTestRenderer = _interopRequireDefault(require("react-test-renderer"));
var _TestUtils = require("../TestUtils");
var _Grid = _interopRequireWildcard(require("./Grid"));
var _defaultCellRangeRenderer = _interopRequireDefault(require("./defaultCellRangeRenderer"));
var _CellMeasurer = require("../CellMeasurer");
var _defaultOverscanIndicesGetter = require("./defaultOverscanIndicesGetter");
var _maxElementSize = require("./utils/maxElementSize.js");
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; }
function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2["default"])(o), (0, _possibleConstructorReturn2["default"])(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2["default"])(t).constructor) : o.apply(t, e)); }
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2["default"])(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
var DEFAULT_COLUMN_WIDTH = 50;
var DEFAULT_HEIGHT = 100;
var DEFAULT_ROW_HEIGHT = 20;
var DEFAULT_WIDTH = 200;
var NUM_ROWS = 100;
var NUM_COLUMNS = 50;
function getScrollbarSize0() {
return 0;
}
function getScrollbarSize20() {
return 20;
}
describe('Grid', function () {
function defaultCellRenderer(_ref) {
var columnIndex = _ref.columnIndex,
key = _ref.key,
rowIndex = _ref.rowIndex,
style = _ref.style;
return /*#__PURE__*/React.createElement("div", {
className: "gridItem",
key: key,
style: style
}, "row:".concat(rowIndex, ", column:").concat(columnIndex));
}
function simulateScroll(_ref2) {
var grid = _ref2.grid,
_ref2$scrollLeft = _ref2.scrollLeft,
scrollLeft = _ref2$scrollLeft === void 0 ? 0 : _ref2$scrollLeft,
_ref2$scrollTop = _ref2.scrollTop,
scrollTop = _ref2$scrollTop === void 0 ? 0 : _ref2$scrollTop;
var target = {
scrollLeft: scrollLeft,
scrollTop: scrollTop
};
grid._scrollingContainer = target; // HACK to work around _onScroll target check
_testUtils.Simulate.scroll((0, _reactDom.findDOMNode)(grid), {
target: target
});
}
function getMarkup() {
var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
return /*#__PURE__*/React.createElement(_Grid["default"], (0, _extends2["default"])({
cellRenderer: defaultCellRenderer,
columnCount: NUM_COLUMNS,
columnWidth: DEFAULT_COLUMN_WIDTH,
getScrollbarSize: getScrollbarSize0,
height: DEFAULT_HEIGHT,
overscanColumnCount: 0,
overscanRowCount: 0,
autoHeight: false,
rowHeight: DEFAULT_ROW_HEIGHT,
rowCount: NUM_ROWS,
width: DEFAULT_WIDTH
}, props));
}
describe('number of rendered children', function () {
it('should render enough children to fill the available area', function () {
var rendered = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup()));
expect(rendered.querySelectorAll('.gridItem').length).toEqual(20); // 5 rows x 4 columns
});
it('should not render more rows than available if the area is not filled', function () {
var rendered = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
rowCount: 2
})));
expect(rendered.querySelectorAll('.gridItem').length).toEqual(8); // 2 rows x 4 columns
});
it('should not render more columns than available if the area is not filled', function () {
var rendered = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
columnCount: 2
})));
expect(rendered.querySelectorAll('.gridItem').length).toEqual(10); // 5 rows x 2 columns
});
// Small performance tweak added in 5.5.6
it('should not render/parent cells that are null or false', function () {
function cellRenderer(_ref3) {
var columnIndex = _ref3.columnIndex,
key = _ref3.key,
rowIndex = _ref3.rowIndex,
style = _ref3.style;
if (columnIndex === 0) {
return null;
} else if (rowIndex === 0) {
return false;
} else {
return /*#__PURE__*/React.createElement("div", {
className: "cell",
key: key,
style: style
}, "row:".concat(rowIndex, ", column:").concat(columnIndex));
}
}
var rendered = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
columnCount: 3,
overscanColumnCount: 0,
overscanRowCount: 0,
rowCount: 3,
cellRenderer: cellRenderer
})));
expect(rendered.querySelectorAll('.cell').length).toEqual(4); // [1,1], [1,2], [2,1], and [2,2]
expect(rendered.textContent).not.toContain('column:0');
expect(rendered.textContent).not.toContain('row:0');
});
it('should scroll to the last existing point when rows are removed', function () {
var grid = (0, _TestUtils.render)(getMarkup({
rowCount: 15
}));
simulateScroll({
grid: grid,
scrollTop: 200
});
var updatedGrid = (0, _TestUtils.render)(getMarkup({
rowCount: 10
}));
expect(updatedGrid.state.scrollTop).toEqual(100);
});
it('should scroll to the last existing point when columns are removed', function () {
var grid = (0, _TestUtils.render)(getMarkup({
columnCount: 12
}));
simulateScroll({
grid: grid,
scrollLeft: 400
});
var updatedGrid = (0, _TestUtils.render)(getMarkup({
columnCount: 8
}));
expect(updatedGrid.state.scrollLeft).toEqual(200);
});
it('should not scroll unseen rows are removed', function () {
(0, _TestUtils.render)(getMarkup({
rowCount: 15
}));
var updatedGrid = (0, _TestUtils.render)(getMarkup({
rowCount: 10
}));
expect(updatedGrid.state.scrollTop).toEqual(0);
});
it('should not scroll when unseen columns are removed', function () {
(0, _TestUtils.render)(getMarkup({
columnCount: 12
}));
var updatedGrid = (0, _TestUtils.render)(getMarkup({
columnCount: 8
}));
expect(updatedGrid.state.scrollLeft).toEqual(0);
});
});
describe('shows and hides scrollbars based on rendered content', function () {
it('should set overflowX:hidden if columns fit within the available width and y-axis has no scrollbar', function () {
var rendered = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
columnCount: 4,
getScrollbarSize: getScrollbarSize20,
rowCount: 5
})));
expect(rendered.style.overflowX).toEqual('hidden');
});
it('should set overflowX:hidden if columns and y-axis scrollbar fit within the available width', function () {
var rendered = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
columnCount: 4,
getScrollbarSize: getScrollbarSize20,
width: 200 + getScrollbarSize20()
})));
expect(rendered.style.overflowX).toEqual('hidden');
});
it('should leave overflowX:auto if columns require more than the available width', function () {
var rendered = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
columnCount: 4,
getScrollbarSize: getScrollbarSize20,
width: 200 - 1,
rowCount: 5
})));
expect(rendered.style.overflowX).not.toEqual('hidden');
});
it('should leave overflowX:auto if columns and y-axis scrollbar require more than the available width', function () {
var rendered = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
columnCount: 4,
getScrollbarSize: getScrollbarSize20,
width: 200 + getScrollbarSize20() - 1
})));
expect(rendered.style.overflowX).not.toEqual('hidden');
});
it('should set overflowY:hidden if rows fit within the available width and xaxis has no scrollbar', function () {
var rendered = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
getScrollbarSize: getScrollbarSize20,
rowCount: 5,
columnCount: 4
})));
expect(rendered.style.overflowY).toEqual('hidden');
});
it('should set overflowY:hidden if rows and x-axis scrollbar fit within the available width', function () {
var rendered = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
getScrollbarSize: getScrollbarSize20,
rowCount: 5,
height: 100 + getScrollbarSize20()
})));
expect(rendered.style.overflowY).toEqual('hidden');
});
it('should leave overflowY:auto if rows require more than the available width', function () {
var rendered = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
getScrollbarSize: getScrollbarSize20,
rowCount: 5,
height: 100 - 1,
columnCount: 4
})));
expect(rendered.style.overflowY).not.toEqual('hidden');
});
it('should leave overflowY:auto if rows and x-axis scrollbar require more than the available width', function () {
var rendered = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
getScrollbarSize: getScrollbarSize20,
rowCount: 5,
height: 100 + getScrollbarSize20() - 1
})));
expect(rendered.style.overflowY).not.toEqual('hidden');
});
it('should accept styles that overwrite calculated ones', function () {
var rendered = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
columnCount: 1,
getScrollbarSize: getScrollbarSize20,
height: 1,
rowCount: 1,
style: {
overflowY: 'visible',
overflowX: 'visible'
},
width: 1
})));
expect(rendered.style.overflowY).toEqual('visible');
expect(rendered.style.overflowX).toEqual('visible');
});
});
/** Tests scrolling via initial props */
describe(':scrollToColumn and :scrollToRow', function () {
it('should scroll to the left', function () {
var grid = (0, _TestUtils.render)(getMarkup({
scrollToColumn: 0
}));
expect(grid.state.scrollLeft).toEqual(0);
});
it('should scroll over to the middle', function () {
var grid = (0, _TestUtils.render)(getMarkup({
scrollToColumn: 24
}));
// 50 columns * 50 item width = 2,500 total item width
// 4 columns can be visible at a time and :scrollLeft is initially 0,
// So the minimum amount of scrolling leaves the 25th item at the right (just scrolled into view).
expect(grid.state.scrollLeft).toEqual(1050);
});
it('should scroll to the far right', function () {
var grid = (0, _TestUtils.render)(getMarkup({
scrollToColumn: 49
}));
// 50 columns * 50 item width = 2,500 total item width
// Target offset for the last item then is 2,500 - 200
expect(grid.state.scrollLeft).toEqual(2300);
});
it('should scroll to the top', function () {
var grid = (0, _TestUtils.render)(getMarkup({
scrollToRow: 0
}));
expect(grid.state.scrollTop).toEqual(0);
});
it('should scroll down to the middle', function () {
var grid = (0, _TestUtils.render)(getMarkup({
scrollToRow: 49
}));
// 100 rows * 20 item height = 2,000 total item height
// 5 rows can be visible at a time and :scrollTop is initially 0,
// So the minimum amount of scrolling leaves the 50th item at the bottom (just scrolled into view).
expect(grid.state.scrollTop).toEqual(900);
});
it('should scroll to the bottom', function () {
var grid = (0, _TestUtils.render)(getMarkup({
scrollToRow: 99
}));
// 100 rows * 20 item height = 2,000 total item height
// Target offset for the last item then is 2,000 - 100
expect(grid.state.scrollTop).toEqual(1900);
});
it('should scroll to a row and column just added', function () {
var grid = (0, _TestUtils.render)(getMarkup());
expect(grid.state.scrollLeft).toEqual(0);
expect(grid.state.scrollTop).toEqual(0);
grid = (0, _TestUtils.render)(getMarkup({
columnCount: NUM_COLUMNS + 1,
rowCount: NUM_ROWS + 1,
scrollToColumn: NUM_COLUMNS,
scrollToRow: NUM_ROWS
}));
expect(grid.state.scrollLeft).toEqual(2350);
expect(grid.state.scrollTop).toEqual(1920);
});
it('should scroll back to a newly-added cell without a change in prop', function () {
var grid = (0, _TestUtils.render)(getMarkup({
columnCount: NUM_COLUMNS,
rowCount: NUM_ROWS,
scrollToColumn: NUM_COLUMNS,
scrollToRow: NUM_ROWS
}));
grid = (0, _TestUtils.render)(getMarkup({
columnCount: NUM_COLUMNS + 1,
rowCount: NUM_ROWS + 1,
scrollToColumn: NUM_COLUMNS,
scrollToRow: NUM_ROWS
}));
expect(grid.state.scrollLeft).toEqual(2350);
expect(grid.state.scrollTop).toEqual(1920);
});
it('should scroll to the correct position for :scrollToAlignment "start"', function () {
var grid = (0, _TestUtils.render)(getMarkup({
scrollToAlignment: 'start',
scrollToColumn: 24,
scrollToRow: 49
}));
// 50 columns * 50 item width = 2,500 total item width
// 100 rows * 20 item height = 2,000 total item height
// 4 columns and 5 rows can be visible at a time.
// The minimum amount of scrolling leaves the specified cell in the bottom/right corner (just scrolled into view).
// Since alignment is set to "start" we should scroll past this point until the cell is aligned top/left.
expect(grid.state.scrollLeft).toEqual(1200);
expect(grid.state.scrollTop).toEqual(980);
});
it('should scroll to the correct position for :scrollToAlignment "end"', function () {
(0, _TestUtils.render)(getMarkup({
scrollToColumn: 99,
scrollToRow: 99
}));
var grid = (0, _TestUtils.render)(getMarkup({
scrollToAlignment: 'end',
scrollToColumn: 24,
scrollToRow: 49
}));
// 50 columns * 50 item width = 2,500 total item width
// 100 rows * 20 item height = 2,000 total item height
// We first scroll past the specified cell and then back.
// The minimum amount of scrolling then should leave the specified cell in the top/left corner (just scrolled into view).
// Since alignment is set to "end" we should scroll past this point until the cell is aligned bottom/right.
expect(grid.state.scrollLeft).toEqual(1050);
expect(grid.state.scrollTop).toEqual(900);
});
it('should scroll to the correct position for :scrollToAlignment "center"', function () {
(0, _TestUtils.render)(getMarkup({
scrollToColumn: 99,
scrollToRow: 99
}));
var grid = (0, _TestUtils.render)(getMarkup({
scrollToAlignment: 'center',
scrollToColumn: 24,
scrollToRow: 49
}));
// 50 columns * 50 item width = 2,500 total item width
// Viewport width is 200
// Column 24 starts at 1,200, center point at 1,225, so...
expect(grid.state.scrollLeft).toEqual(1125);
// 100 rows * 20 item height = 2,000 total item height
// Viewport height is 100
// Row 49 starts at 980, center point at 990, so...
expect(grid.state.scrollTop).toEqual(940);
});
// Tests issue #691
it('should set the correct :scrollLeft after height increases from 0', function () {
_TestUtils.render.unmount();
expect((0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
height: 0,
scrollToColumn: 24
}))).scrollLeft || 0).toEqual(0);
expect((0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
height: 100,
scrollToColumn: 24
}))).scrollLeft).toEqual(1050);
});
// Tests issue #691
it('should set the correct :scrollTop after width increases from 0', function () {
_TestUtils.render.unmount();
expect((0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
scrollToRow: 49,
width: 0
}))).scrollTop || 0).toEqual(0);
expect((0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
scrollToRow: 49,
width: 100
}))).scrollTop).toEqual(900);
});
// Tests issue #218
it('should set the correct :scrollTop after row and column counts increase from 0', function () {
var expectedScrollTop = 100 * DEFAULT_ROW_HEIGHT - DEFAULT_HEIGHT + DEFAULT_ROW_HEIGHT;
(0, _TestUtils.render)(getMarkup({
columnCount: 0,
rowCount: 150,
scrollToRow: 100
}));
expect((0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
columnCount: 150,
rowCount: 150,
scrollToRow: 100
}))).scrollTop).toEqual(expectedScrollTop);
});
it('should support scrollToCell() public method', function () {
var grid = (0, _TestUtils.render)(getMarkup());
expect(grid.state.scrollLeft).toEqual(0);
expect(grid.state.scrollTop).toEqual(0);
grid.scrollToCell({
columnIndex: 24,
rowIndex: 49
});
// 50 columns * 50 item width = 2,500 total item width
// 4 columns can be visible at a time and :scrollLeft is initially 0,
// So the minimum amount of scrolling leaves the 25th item at the right (just scrolled into view).
expect(grid.state.scrollLeft).toEqual(1050);
// 100 rows * 20 item height = 2,000 total item height
// 5 rows can be visible at a time and :scrollTop is initially 0,
// So the minimum amount of scrolling leaves the 50th item at the bottom (just scrolled into view).
expect(grid.state.scrollTop).toEqual(900);
// Change column without affecting row
grid.scrollToCell({
columnIndex: 49
});
expect(grid.state.scrollLeft).toEqual(2300);
expect(grid.state.scrollTop).toEqual(900);
// Change row without affecting column
grid.scrollToCell({
rowIndex: 99
});
expect(grid.state.scrollLeft).toEqual(2300);
expect(grid.state.scrollTop).toEqual(1900);
});
it('should support scrollToPosition() public method', function () {
var grid = (0, _TestUtils.render)(getMarkup());
expect(grid.state.scrollLeft).toEqual(0);
expect(grid.state.scrollTop).toEqual(0);
grid.scrollToPosition({
scrollLeft: 50,
scrollTop: 100
});
expect(grid.state.scrollLeft).toEqual(50);
expect(grid.state.scrollTop).toEqual(100);
// Change column without affecting row
grid.scrollToPosition({
scrollLeft: 25
});
expect(grid.state.scrollLeft).toEqual(25);
expect(grid.state.scrollTop).toEqual(100);
// Change row without affecting column
grid.scrollToPosition({
scrollTop: 50
});
expect(grid.state.scrollLeft).toEqual(25);
expect(grid.state.scrollTop).toEqual(50);
});
it('should support handleScrollEvent() public method', function () {
var grid = (0, _TestUtils.render)(getMarkup());
expect(grid.state.scrollLeft).toEqual(0);
expect(grid.state.scrollTop).toEqual(0);
grid.handleScrollEvent({
scrollLeft: 50,
scrollTop: 100
});
expect(grid.state.isScrolling).toEqual(true);
expect(grid.state.scrollLeft).toEqual(50);
expect(grid.state.scrollTop).toEqual(100);
});
it('should support getOffsetForCell() public method', function () {
var grid = (0, _TestUtils.render)(getMarkup());
var _grid$getOffsetForCel = grid.getOffsetForCell({
columnIndex: 24,
rowIndex: 49
}),
scrollLeft = _grid$getOffsetForCel.scrollLeft,
scrollTop = _grid$getOffsetForCel.scrollTop;
// 50 columns * 50 item width = 2,500 total item width
// 4 columns can be visible at a time and :scrollLeft is initially 0,
// So the minimum amount of scrolling leaves the 25th item at the right (just scrolled into view).
expect(scrollLeft).toEqual(1050);
// 100 rows * 20 item height = 2,000 total item height
// 5 rows can be visible at a time and :scrollTop is initially 0,
// So the minimum amount of scrolling leaves the 50th item at the bottom (just scrolled into view).
expect(scrollTop).toEqual(900);
});
it('should support getTotalRowsHeight() public method', function () {
var grid = (0, _TestUtils.render)(getMarkup());
grid.recomputeGridSize();
var totalHeight = grid.getTotalRowsHeight();
// 100 rows * 20 item height = 2,000 total item height
expect(totalHeight).toEqual(2000);
});
it('should support getTotalColumnsWidth() public method', function () {
var grid = (0, _TestUtils.render)(getMarkup());
grid.recomputeGridSize();
var totalWidth = grid.getTotalColumnsWidth();
// 50 columns * 50 item width = 2,500 total item width
expect(totalWidth).toEqual(2500);
});
// See issue #565
it('should update scroll position to account for changed cell sizes within a function prop wrapper', function () {
var _rowHeight = 20;
var props = {
height: 100,
rowCount: 100,
rowHeight: function rowHeight(_ref4) {
var index = _ref4.index;
return index === 99 ? _rowHeight : 20;
},
scrollToRow: 99
};
var grid = (0, _TestUtils.render)(getMarkup(props));
var node = (0, _reactDom.findDOMNode)(grid);
expect(node.scrollTop).toBe(1900);
_rowHeight = 40;
grid.recomputeGridSize({
rowIndex: 99
});
expect(node.scrollTop).toBe(1920);
});
it('should not restore scrollLeft when scrolling left and recomputeGridSize with columnIndex smaller than scrollToColumn', function () {
var props = {
columnWidth: 50,
columnCount: 100,
height: 100,
rowCount: 100,
rowHeight: 20,
scrollToColumn: 50,
scrollToRow: 50,
width: 100
};
var grid = (0, _TestUtils.render)(getMarkup(props));
expect(grid.state.scrollLeft).toEqual(2450);
simulateScroll({
grid: grid,
scrollLeft: 2250
});
expect(grid.state.scrollLeft).toEqual(2250);
expect(grid.state.scrollDirectionHorizontal).toEqual(_defaultOverscanIndicesGetter.SCROLL_DIRECTION_BACKWARD);
grid.recomputeGridSize({
columnIndex: 30
});
expect(grid.state.scrollLeft).toEqual(2250);
});
it('should not restore scrollTop when scrolling up and recomputeGridSize with rowIndex smaller than scrollToRow', function () {
var props = {
columnWidth: 50,
columnCount: 100,
height: 100,
rowCount: 100,
rowHeight: 20,
scrollToColumn: 50,
scrollToRow: 50,
width: 100
};
var grid = (0, _TestUtils.render)(getMarkup(props));
expect(grid.state.scrollTop).toEqual(920);
simulateScroll({
grid: grid,
scrollTop: 720
});
expect(grid.state.scrollTop).toEqual(720);
expect(grid.state.scrollDirectionVertical).toEqual(_defaultOverscanIndicesGetter.SCROLL_DIRECTION_BACKWARD);
grid.recomputeGridSize({
rowIndex: 20
});
expect(grid.state.scrollTop).toEqual(720);
});
it('should restore scroll offset for column when row count increases from 0 (and vice versa)', function () {
var props = {
columnWidth: 50,
columnCount: 100,
height: 100,
rowCount: 100,
rowHeight: 20,
scrollToColumn: 50,
scrollToRow: 50,
width: 100
};
var grid = (0, _TestUtils.render)(getMarkup(props));
expect(grid.state.scrollLeft).toEqual(2450);
expect(grid.state.scrollTop).toEqual(920);
(0, _TestUtils.render)(getMarkup(_objectSpread(_objectSpread({}, props), {}, {
columnCount: 0
})));
expect(grid.state.scrollLeft).toEqual(0);
expect(grid.state.scrollTop).toEqual(0);
(0, _TestUtils.render)(getMarkup(props));
expect(grid.state.scrollLeft).toEqual(2450);
expect(grid.state.scrollTop).toEqual(920);
(0, _TestUtils.render)(getMarkup(_objectSpread(_objectSpread({}, props), {}, {
rowCount: 0
})));
expect(grid.state.scrollLeft).toEqual(0);
expect(grid.state.scrollTop).toEqual(0);
(0, _TestUtils.render)(getMarkup(props));
expect(grid.state.scrollLeft).toEqual(2450);
expect(grid.state.scrollTop).toEqual(920);
});
it('should take scrollbar size into account when aligning cells', function () {
var grid = (0, _TestUtils.render)(getMarkup({
columnWidth: 50,
columnCount: 100,
getScrollbarSize: getScrollbarSize20,
height: 100,
rowCount: 100,
rowHeight: 20,
scrollToColumn: 50,
scrollToRow: 50,
width: 100
}));
expect(grid.state.scrollLeft).toEqual(2450 + getScrollbarSize20());
expect(grid.state.scrollTop).toEqual(920 + getScrollbarSize20());
});
});
describe('property updates', function () {
it('should update :scrollToColumn position when :columnWidth changes', function () {
var grid = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
scrollToColumn: 25
})));
expect(grid.textContent).toContain('column:25');
// Making columns taller pushes name off/beyond the scrolled area
grid = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
scrollToColumn: 25,
columnWidth: 20
})));
expect(grid.textContent).toContain('column:25');
});
it('should update :scrollToRow position when :rowHeight changes', function () {
var grid = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
scrollToRow: 50
})));
expect(grid.textContent).toContain('row:50');
// Making rows taller pushes name off/beyond the scrolled area
grid = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
scrollToRow: 50,
rowHeight: 20
})));
expect(grid.textContent).toContain('row:50');
});
it('should update :scrollToColumn position when :width changes', function () {
var grid = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
scrollToColumn: 25
})));
expect(grid.textContent).toContain('column:25');
// Making the grid narrower leaves only room for 1 item
grid = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
scrollToColumn: 25,
width: 50
})));
expect(grid.textContent).toContain('column:25');
});
it('should update :scrollToRow position when :height changes', function () {
var grid = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
scrollToRow: 50
})));
expect(grid.textContent).toContain('row:50');
// Making the grid shorter leaves only room for 1 item
grid = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
scrollToRow: 50,
height: 20
})));
expect(grid.textContent).toContain('row:50');
});
it('should update :scrollToColumn position when :scrollToColumn changes', function () {
var grid = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup()));
expect(grid.textContent).not.toContain('column:25');
grid = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
scrollToColumn: 25
})));
expect(grid.textContent).toContain('column:25');
});
it('should update :scrollToRow position when :scrollToRow changes', function () {
var grid = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup()));
expect(grid.textContent).not.toContain('row:50');
grid = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
scrollToRow: 50
})));
expect(grid.textContent).toContain('row:50');
});
it('should update scroll position if size shrinks smaller than the current scroll', function () {
var grid = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
scrollToColumn: 250
})));
grid = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup()));
grid = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
scrollToColumn: 250,
columnCount: 10
})));
expect(grid.textContent).toContain('column:9');
});
it('should update scroll position if size shrinks smaller than the current scroll', function () {
var grid = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
scrollToRow: 500
})));
grid = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup()));
grid = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
scrollToRow: 500,
rowCount: 10
})));
expect(grid.textContent).toContain('row:9');
});
});
describe('noContentRenderer', function () {
it('should call :noContentRenderer if :columnCount is 0', function () {
var list = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
noContentRenderer: function noContentRenderer() {
return /*#__PURE__*/React.createElement("div", null, "No data");
},
columnCount: 0
})));
expect(list.textContent).toEqual('No data');
});
it('should call :noContentRenderer if :rowCount is 0', function () {
var list = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
noContentRenderer: function noContentRenderer() {
return /*#__PURE__*/React.createElement("div", null, "No data");
},
rowCount: 0
})));
expect(list.textContent).toEqual('No data');
});
// Sanity check for bvaughn/react-virtualized/pull/348
it('should render an empty body if :rowCount or :columnCount changes to 0', function () {
function noContentRenderer() {
return /*#__PURE__*/React.createElement("div", null, "No data");
}
var list = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
noContentRenderer: noContentRenderer
})));
expect(list.textContent).not.toEqual('No data');
list = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
noContentRenderer: noContentRenderer,
rowCount: 0
})));
expect(list.textContent).toEqual('No data');
list = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
noContentRenderer: noContentRenderer
})));
expect(list.textContent).not.toEqual('No data');
list = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
columnCount: 0,
noContentRenderer: noContentRenderer
})));
expect(list.textContent).toEqual('No data');
});
it('should render an empty body if :columnCount is 0 and there is no :noContentRenderer', function () {
var list = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
columnCount: 0
})));
expect(list.textContent).toEqual('');
});
it('should render an empty body if :rowCount is 0 and there is no :noContentRenderer', function () {
var list = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
rowCount: 0
})));
expect(list.textContent).toEqual('');
});
it('should render an empty body there is a :noContentRenderer but :height or :width are 0', function () {
var list = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
height: 0,
noContentRenderer: function noContentRenderer() {
return /*#__PURE__*/React.createElement("div", null, "No data");
}
})));
expect(list.textContent).toEqual('');
list = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
noContentRenderer: function noContentRenderer() {
return /*#__PURE__*/React.createElement("div", null, "No data");
},
width: 0
})));
expect(list.textContent).toEqual('');
});
});
describe('onSectionRendered', function () {
it('should call :onSectionRendered if at least one cell is rendered', function () {
var columnStartIndex, columnStopIndex, rowStartIndex, rowStopIndex;
(0, _TestUtils.render)(getMarkup({
onSectionRendered: function onSectionRendered(params) {
var _params;
return _params = params, columnStartIndex = _params.columnStartIndex, columnStopIndex = _params.columnStopIndex, rowStartIndex = _params.rowStartIndex, rowStopIndex = _params.rowStopIndex, _params;
}
}));
expect(columnStartIndex).toEqual(0);
expect(columnStopIndex).toEqual(3);
expect(rowStartIndex).toEqual(0);
expect(rowStopIndex).toEqual(4);
});
it('should not call :onSectionRendered unless the column or row start or stop indices have changed', function () {
var numCalls = 0;
var columnStartIndex, columnStopIndex, rowStartIndex, rowStopIndex;
var onSectionRendered = function onSectionRendered(params) {
columnStartIndex = params.columnStartIndex;
columnStopIndex = params.columnStopIndex;
rowStartIndex = params.rowStartIndex;
rowStopIndex = params.rowStopIndex;
numCalls++;
};
(0, _TestUtils.render)(getMarkup({
onSectionRendered: onSectionRendered
}));
expect(numCalls).toEqual(1);
expect(columnStartIndex).toEqual(0);
expect(columnStopIndex).toEqual(3);
expect(rowStartIndex).toEqual(0);
expect(rowStopIndex).toEqual(4);
(0, _TestUtils.render)(getMarkup({
onSectionRendered: onSectionRendered
}));
expect(numCalls).toEqual(1);
expect(columnStartIndex).toEqual(0);
expect(columnStopIndex).toEqual(3);
expect(rowStartIndex).toEqual(0);
expect(rowStopIndex).toEqual(4);
});
it('should call :onSectionRendered if the row or column start or stop indices have changed', function () {
var numCalls = 0;
var columnStartIndex, columnStopIndex, rowStartIndex, rowStopIndex;
var onSectionRendered = function onSectionRendered(params) {
columnStartIndex = params.columnStartIndex;
columnStopIndex = params.columnStopIndex;
rowStartIndex = params.rowStartIndex;
rowStopIndex = params.rowStopIndex;
numCalls++;
};
(0, _TestUtils.render)(getMarkup({
onSectionRendered: onSectionRendered
}));
expect(columnStartIndex).toEqual(0);
expect(columnStopIndex).toEqual(3);
expect(rowStartIndex).toEqual(0);
expect(rowStopIndex).toEqual(4);
(0, _TestUtils.render)(getMarkup({
height: 50,
onSectionRendered: onSectionRendered
}));
expect(numCalls).toEqual(2);
expect(columnStartIndex).toEqual(0);
expect(columnStopIndex).toEqual(3);
expect(rowStartIndex).toEqual(0);
expect(rowStopIndex).toEqual(2);
(0, _TestUtils.render)(getMarkup({
height: 50,
onSectionRendered: onSectionRendered,
width: 100
}));
expect(numCalls).toEqual(3);
expect(columnStartIndex).toEqual(0);
expect(columnStopIndex).toEqual(1);
expect(rowStartIndex).toEqual(0);
expect(rowStopIndex).toEqual(2);
});
it('should not call :onSectionRendered if no cells are rendered', function () {
var numCalls = 0;
(0, _TestUtils.render)(getMarkup({
height: 0,
onSectionRendered: function onSectionRendered() {
return numCalls++;
}
}));
expect(numCalls).toEqual(0);
});
});
describe(':scrollLeft and :scrollTop properties', function () {
it('should render correctly when an initial :scrollLeft and :scrollTop properties are specified', function () {
var columnStartIndex, columnStopIndex, rowStartIndex, rowStopIndex;
(0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
onSectionRendered: function onSectionRendered(params) {
var _params2;
return _params2 = params, columnStartIndex = _params2.columnStartIndex, columnStopIndex = _params2.columnStopIndex, rowStartIndex = _params2.rowStartIndex, rowStopIndex = _params2.rowStopIndex, _params2;
},
scrollLeft: 250,
scrollTop: 100
})));
expect(rowStartIndex).toEqual(5);
expect(rowStopIndex).toEqual(9);
expect(columnStartIndex).toEqual(5);
expect(columnStopIndex).toEqual(8);
});
it('should render correctly when :scrollLeft and :scrollTop properties are updated', function () {
var columnStartIndex, columnStopIndex, rowStartIndex, rowStopIndex;
(0, _TestUtils.render)(getMarkup({
onSectionRendered: function onSectionRendered(params) {
var _params3;
return _params3 = params, columnStartIndex = _params3.columnStartIndex, columnStopIndex = _params3.columnStopIndex, rowStartIndex = _params3.rowStartIndex, rowStopIndex = _params3.rowStopIndex, _params3;
}
}));
expect(rowStartIndex).toEqual(0);
expect(rowStopIndex).toEqual(4);
expect(columnStartIndex).toEqual(0);
expect(columnStopIndex).toEqual(3);
(0, _TestUtils.render)(getMarkup({
onSectionRendered: function onSectionRendered(params) {
var _params4;
return _params4 = params, columnStartIndex = _params4.columnStartIndex, columnStopIndex = _params4.columnStopIndex, rowStartIndex = _params4.rowStartIndex, rowStopIndex = _params4.rowStopIndex, _params4;
},
scrollLeft: 250,
scrollTop: 100
}));
expect(rowStartIndex).toEqual(5);
expect(rowStopIndex).toEqual(9);
expect(columnStartIndex).toEqual(5);
expect(columnStopIndex).toEqual(8);
});
});
describe('styles, classNames, ids, and roles', function () {
it('should use the expected global CSS classNames', function () {
var rendered = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup()));
expect(rendered.className).toEqual('ReactVirtualized__Grid');
});
it('should use a custom :className if specified', function () {
var rendered = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
className: 'foo'
})));
expect(rendered.className).toContain('foo');
});
it('should use a custom :id if specified', function () {
var rendered = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
id: 'bar'
})));
expect(rendered.getAttribute('id')).toEqual('bar');
});
it('should use a custom :style if specified', function () {
var style = {
backgroundColor: 'red'
};
var rendered = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
style: style
})));
expect(rendered.style.backgroundColor).toEqual('red');
});
it('should use a custom :containerStyle if specified', function () {
var containerStyle = {
backgroundColor: 'red'
};
var rendered = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
containerStyle: containerStyle
})));
expect(rendered.querySelector('.ReactVirtualized__Grid__innerScrollContainer').style.backgroundColor).toEqual('red');
});
it('should have the gridcell role', function () {
var containerStyle = {
backgroundColor: 'red'
};
var rendered = (0, _reactDom.findDOMNode)((0, _TestUtils.render)(getMarkup({
containerStyle: containerStyle
})));
expect(rendered.querySelectorAll('[role="gridcell"]').length).toEqual(20);
});
});
describe('onScroll', function () {
it('should trigger callback when component is mounted', function () {
var onScrollCalls = [];
(0, _TestUtils.render)(getMarkup({
onScroll: function onScroll(params) {
return onScrollCalls.push(params);
},
scrollLeft: 50,
scrollTop: 100
}));
expect(onScrollCalls).toEqual([{
clientHeight: 100,
clientWidth: 200,
scrollHeight: 2000,
scrollLeft: 50,
scrollTop: 100,
scrollWidth: 2500
}]);
});
it('should trigger callback when component scrolls horizontally', function () {
var onScrollCalls = [];
var grid = (0, _TestUtils.render)(getMarkup({
onScroll: function onScroll(params) {
return onScrollCalls.push(params);
}
}));
simulateScroll({
grid: grid,
scrollLeft: 100,
scrollTop: 0
});
expect(onScrollCalls.length).toEqual(2);
expect(onScrollCalls[1]).toEqual({
clientHeight: 100,
clientWidth: 200,
scrollHeight: 2000,
scrollLeft: 100,
scrollTop: 0,
scrollWidth: 2500
});
});
it('should trigger callback when component scrolls vertically', function () {
var onScrollCalls = [];
var grid = (0, _TestUtils.render)(getMarkup({
onScroll: function onScroll(params) {
return onScrollCalls.push(params);
}
}));
simulateScroll({
grid: grid,
scrollLeft: 0,
scrollTop: 100
});
expect(onScrollCalls.length).toEqual(2);
expect(onScrollCalls[1]).toEqual({
clientHeight: 100,
clientWidth: 200,
scrollHeight: 2000,
scrollLeft: 0,
scrollTop: 100,
scrollWidth: 2500
});
});
it('should trigger callback with scrollLeft of 0 when total columns width is less than width', function () {
var onScrollCalls = [];
var grid = (0, _TestUtils.render)(getMarkup({
columnCount: 1,
columnWidth: 50,
onScroll: function onScroll(params) {
return onScrollCalls.push(params);
},
scrollLeft: 0,
scrollTop: 10,
width: 200
}));
simulateScroll({
grid: grid,
scrollLeft: 0,
scrollTop: 0
});
expect(onScrollCalls.length).toEqual(2);
expect(onScrollCalls[1]).toEqual({
clientHeight: 100,
clientWidth: 200,
scrollHeight: 2000,
scrollLeft: 0,
scrollTop: 0,
scrollWidth: 50
});
});
it('should trigger callback with scrollTop of 0 when total rows height is less than height', function () {
var onScrollCalls = [];
var grid = (0, _TestUtils.render)(getMarkup({
rowCount: 1,
rowHeight: 50,
onScroll: function onScroll(params) {
return onScrollCalls.push(params);
},
scrollLeft: 0,
scrollTop: 10,
height: 200
}));
simulateScroll({
grid: grid,
scrollLeft: 0,
scrollTop: 0
});
expect(onScrollCalls.length).toEqual(2);
expect(onScrollCalls[1]).toEqual({
clientHeight: 200,
clientWidth: 200,
scrollHeight: 50,
scrollLeft: 0,
scrollTop: 0,
scrollWidth: 2500
});
});
// Support use-cases like WindowScroller; enable them to stay in sync with scroll-to-cell changes.
it('should trigger when :scrollToColumn or :scrollToRow are changed via props', function () {
var onScrollCalls = [];
(0, _TestUtils.render)(getMarkup());
(0, _TestUtils.render)(getMarkup({
onScroll: function onScroll(params) {
return onScrollCalls.push(params);
},
scrollToColumn: 24,
scrollToRow: 49
}));
expect(onScrollCalls).toEqual([{
clientHeight: 100,
clientWidth: 200,
scrollHeight: 2000,
scrollLeft: 1050,
scrollTop: 900,
scrollWidth: 2500
}]);
});
});
describe('overscanColumnCount & overscanRowCount', function () {
function createHelper() {
var _columnOverscanStartIndex, _columnOverscanStopIndex, _columnStartIndex, _columnStopIndex, _rowOverscanStartIndex, _rowOverscanStopIndex, _rowStartIndex, _rowStopIndex;
function onSectionRendered(params) {
_columnOverscanStartIndex = params.columnOverscanStartIndex;
_columnOverscanStopIndex = params.columnOverscanStopIndex;
_columnStartIndex = params.columnStartIndex;
_columnStopIndex = params.columnStopIndex;
_rowOverscanStartIndex = params.rowOverscanStartIndex;
_rowOverscanStopIndex = params.rowOverscanStopIndex;
_rowStartIndex = params.rowStartIndex;
_rowStopIndex = params.rowStopIndex;
}
return {
columnOverscanStartIndex: function columnOverscanStartIndex() {
return _columnOverscanStartIndex;
},
columnOverscanStopIndex: function columnOverscanStopIndex() {
return _columnOverscanStopIndex;
},
columnStartIndex: function columnStartIndex() {
return _columnStartIndex;
},
columnStopIndex: function columnStopIndex() {
return _columnStopIndex;
},
onSectionRendered: onSectionRendered,
rowOverscanStartIndex: function rowOverscanStartIndex() {
return _rowOverscanStartIndex;
},
rowOverscanStopIndex: function rowOverscanStopIndex() {
return _rowOverscanStopIndex;
},
rowStartIndex: function rowStartIndex() {
return _rowStartIndex;
},
rowStopIndex: function rowStopIndex() {
return _rowStopIndex;
}
};
}
it('should not overscan if disabled', function () {
var helper = createHelper();
(0, _TestUtils.render)(getMarkup({
onSectionRendered: helper.onSectionRendered
}));
expect(helper.columnOverscanStartIndex()).toEqual(helper.columnStartIndex());
expect(helper.columnOverscanStopIndex()).toEqual(helper.columnStopIndex());
expect(helper.rowOverscanStartIndex()).toEqual(helper.rowStartIndex());
expect(helper.rowOverscanStopIndex()).toEqual(helper.rowStopIndex());
});
it('should overscan the specified amount', function () {
var helper = createHelper();
(0, _TestUtils.render)(getMarkup({
onSectionRendered: helper.onSectionRendered,
overscanColumnCount: 2,
overscanRowCount: 5,
scrollToColumn: 25,
scrollToRow: 50
}));
expect(helper.columnOverscanStartIndex()).toEqual(22);
expect(helper.columnOverscanStopIndex()).toEqual(27);
expect(helper.columnStartIndex()).toEqual(22);
expect(helper.columnStopIndex()).toEqual(25);
expect(helper.rowOverscanStartIndex()).toEqual(46);
expect(helper.rowOverscanStopIndex()).toEqual(55);
expect(helper.rowStartIndex()).toEqual(46);
expect(helper.rowStopIndex()).toEqual(50);
});
it('should not overscan beyond the bounds of the grid', function () {
var helper = createHelper();
(0, _TestUtils.render)(getMarkup({
onSectionRendered: helper.onSectionRendered,
columnCount: 6,
overscanColumnCount: 10,
overscanRowCount: 10,
rowCount: 5
}));
expect(helper.columnOverscanStartIndex()