@shopify/flash-list
Version:
FlashList is a more performant FlatList replacement
254 lines • 12.4 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var react_native_1 = require("react-native");
require("@quilted/react-testing/matchers");
var recyclerlistview_1 = require("recyclerlistview");
var react_1 = tslib_1.__importDefault(require("react"));
var mountMasonryFlashList_1 = require("./helpers/mountMasonryFlashList");
describe("MasonryFlashList", function () {
beforeEach(function () {
jest.clearAllMocks();
jest.useFakeTimers();
});
it("renders items and has 3 internal lists", function () {
var masonryFlashList = (0, mountMasonryFlashList_1.mountMasonryFlashList)();
expect(masonryFlashList.findAll(recyclerlistview_1.ProgressiveListView).length).toBe(3);
expect(masonryFlashList).toContainReactComponent(react_native_1.Text, { children: "One" });
expect(masonryFlashList).toContainReactComponent(recyclerlistview_1.ProgressiveListView, {
isHorizontal: false,
});
masonryFlashList.unmount();
});
it("invokes renderItem with columnIndex and columnSpan", function () {
var mockRenderItem = jest.fn(function () { return null; });
var masonryFlashList = (0, mountMasonryFlashList_1.mountMasonryFlashList)({
renderItem: mockRenderItem,
data: ["One", "Two", "Three"],
numColumns: 3,
});
expect(mockRenderItem).toHaveBeenCalledWith(expect.objectContaining({
columnIndex: 0,
columnSpan: 1,
}));
expect(mockRenderItem).toHaveBeenCalledWith(expect.objectContaining({
columnIndex: 1,
columnSpan: 1,
}));
expect(mockRenderItem).toHaveBeenCalledWith(expect.objectContaining({
columnSpan: 1,
columnIndex: 2,
}));
masonryFlashList.unmount();
});
it("raised onLoad event only when first internal child mounts", function () {
var _a;
var onLoadMock = jest.fn();
var ref = react_1.default.createRef();
var masonryFlashList = (0, mountMasonryFlashList_1.mountMasonryFlashList)({
onLoad: onLoadMock,
}, ref);
expect(onLoadMock).not.toHaveBeenCalled();
(_a = masonryFlashList.findAll(recyclerlistview_1.ProgressiveListView)[1]) === null || _a === void 0 ? void 0 : _a.instance.onItemLayout(0);
expect(onLoadMock).toHaveBeenCalledTimes(1);
// on load shouldn't be passed to wrapper list
expect(ref.current.props.onLoad).toBeUndefined();
masonryFlashList.unmount();
});
it("can resize columns using getColumnFlex", function () {
var masonryFlashList = (0, mountMasonryFlashList_1.mountMasonryFlashList)({
getColumnFlex: function (_, column) { return (column === 0 ? 1 : 3); },
});
var progressiveListView = masonryFlashList.find(recyclerlistview_1.ProgressiveListView).instance;
expect(progressiveListView.getLayout(0).width).toBe(100);
expect(progressiveListView.getLayout(1).width).toBe(300);
expect(masonryFlashList.findAll(recyclerlistview_1.ProgressiveListView).length).toBe(3);
masonryFlashList.findAll(recyclerlistview_1.ProgressiveListView).forEach(function (plv, index) {
if (index === 1) {
expect(plv.instance.props.layoutSize.width).toBe(100);
}
if (index === 2) {
expect(plv.instance.props.layoutSize.width).toBe(300);
}
});
masonryFlashList.unmount();
});
it("mounts a single ScrollView", function () {
var masonryFlashList = (0, mountMasonryFlashList_1.mountMasonryFlashList)();
expect(masonryFlashList.findAll(react_native_1.ScrollView)).toHaveLength(1);
masonryFlashList.unmount();
});
it("forwards single onScroll event to external listener", function () {
var _a;
var onScrollMock = jest.fn();
var masonryFlashList = (0, mountMasonryFlashList_1.mountMasonryFlashList)({
onScroll: onScrollMock,
});
(_a = masonryFlashList.find(react_native_1.ScrollView)) === null || _a === void 0 ? void 0 : _a.instance.props.onScroll({
nativeEvent: { contentOffset: { x: 0, y: 0 } },
});
expect(onScrollMock).toHaveBeenCalledTimes(1);
masonryFlashList.unmount();
});
it("updates scroll offset of all internal lists", function () {
var _a;
var onScrollMock = jest.fn();
var masonryFlashList = (0, mountMasonryFlashList_1.mountMasonryFlashList)({
onScroll: onScrollMock,
});
(_a = masonryFlashList.find(react_native_1.ScrollView)) === null || _a === void 0 ? void 0 : _a.instance.props.onScroll({
nativeEvent: { contentOffset: { x: 0, y: 100 } },
});
masonryFlashList.findAll(recyclerlistview_1.ProgressiveListView).forEach(function (list) {
expect(list.instance.getCurrentScrollOffset()).toBe(100);
});
masonryFlashList.unmount();
});
it("has a valid ref object", function () {
var ref = react_1.default.createRef();
var masonryFlashList = (0, mountMasonryFlashList_1.mountMasonryFlashList)({}, ref);
expect(ref.current).toBeDefined();
masonryFlashList.unmount();
});
it("forwards overrideItemLayout to internal lists", function () {
var overrideItemLayout = jest.fn(function (layout) {
layout.size = 300;
});
var masonryFlashList = (0, mountMasonryFlashList_1.mountMasonryFlashList)({
overrideItemLayout: overrideItemLayout,
});
expect(masonryFlashList.findAll(recyclerlistview_1.ProgressiveListView).length).toBe(3);
masonryFlashList.findAll(recyclerlistview_1.ProgressiveListView).forEach(function (list, index) {
if (index !== 0) {
expect(list.instance.getLayout(0).height).toBe(300);
}
});
masonryFlashList.unmount();
});
it("forwards keyExtractor to internal list", function () {
var keyExtractor = function (_, index) { return (index + 1).toString(); };
var masonryFlashList = (0, mountMasonryFlashList_1.mountMasonryFlashList)({
keyExtractor: keyExtractor,
});
expect(masonryFlashList.findAll(recyclerlistview_1.ProgressiveListView).length).toBe(3);
expect(masonryFlashList
.findAll(recyclerlistview_1.ProgressiveListView)[0]
.instance.props.dataProvider.getStableId(0)).toBe("0");
expect(masonryFlashList
.findAll(recyclerlistview_1.ProgressiveListView)[1]
.instance.props.dataProvider.getStableId(0)).toBe("1");
expect(masonryFlashList
.findAll(recyclerlistview_1.ProgressiveListView)[2]
.instance.props.dataProvider.getStableId(0)).toBe("2");
masonryFlashList.unmount();
});
it("correctly maps list indices to actual indices", function () {
var data = new Array(20).fill(0).map(function (_, index) { return index.toString(); });
var getItemType = function (item, index) {
expect(index.toString()).toBe(item);
return 0;
};
var renderItem = function (_a) {
var item = _a.item, index = _a.index;
expect(index.toString()).toBe(item);
return null;
};
var overrideItemLayout = function (layout, item, index) {
expect(index.toString()).toBe(item);
};
var keyExtractor = function (item, index) {
expect(index.toString()).toBe(item);
return index.toString();
};
var onViewableItemsChanged = function (info) {
info.viewableItems.forEach(function (viewToken) {
var _a;
expect((_a = viewToken.index) === null || _a === void 0 ? void 0 : _a.toString()).toBe(viewToken.item);
});
};
var masonryFlashList = (0, mountMasonryFlashList_1.mountMasonryFlashList)({
data: data,
renderItem: renderItem,
getItemType: getItemType,
overrideItemLayout: overrideItemLayout,
keyExtractor: keyExtractor,
onViewableItemsChanged: onViewableItemsChanged,
});
jest.advanceTimersByTime(1000);
masonryFlashList.unmount();
});
it("internal list height should be derived from the parent and width from itself", function () {
var masonryFlashList = (0, mountMasonryFlashList_1.mountMasonryFlashList)({
testID: "MasonryProxyScrollView",
});
expect(masonryFlashList.findAll(recyclerlistview_1.ProgressiveListView).length).toBe(3);
masonryFlashList.findAll(react_native_1.View).forEach(function (view) {
var _a, _b;
(_b = (_a = view.props) === null || _a === void 0 ? void 0 : _a.onLayout) === null || _b === void 0 ? void 0 : _b.call(_a, {
nativeEvent: { layout: { width: 500, height: 500 } },
});
});
masonryFlashList.findAll(recyclerlistview_1.ProgressiveListView).forEach(function (list, index) {
if (index !== 0) {
expect(list.instance.getRenderedSize().width).toBe(500);
expect(list.instance.getRenderedSize().height).toBe(900);
}
});
masonryFlashList.unmount();
});
it("can optimize item arrangement", function () {
var columnCount = 3;
var data = new Array(999).fill(null).map(function (_, index) {
return "1";
});
var masonryFlashList = (0, mountMasonryFlashList_1.mountMasonryFlashList)({
data: data,
optimizeItemArrangement: true,
numColumns: columnCount,
overrideItemLayout: function (layout, _, index, __, ___) {
layout.size = ((index * 10) % 100) + 100 / ((index % columnCount) + 1);
},
});
expect(masonryFlashList.findAll(recyclerlistview_1.ProgressiveListView).length).toBe(4);
// I've verified that the following values are correct by observing the algorithm in action
// Captured values will help prevent regression in the future
expect(Math.floor(masonryFlashList
.findAll(recyclerlistview_1.ProgressiveListView)[1]
.instance.getContentDimension().height)).toBe(35306);
expect(Math.floor(masonryFlashList
.findAll(recyclerlistview_1.ProgressiveListView)[2]
.instance.getContentDimension().height)).toBe(35313);
expect(Math.floor(masonryFlashList
.findAll(recyclerlistview_1.ProgressiveListView)[3]
.instance.getContentDimension().height)).toBe(35339);
});
it("applies horizontal content container padding to the list", function () {
var masonryFlashList = (0, mountMasonryFlashList_1.mountMasonryFlashList)({
numColumns: 4,
contentContainerStyle: { paddingHorizontal: 10 },
});
expect(masonryFlashList.findAll(recyclerlistview_1.ProgressiveListView).length).toBe(5);
masonryFlashList.findAll(recyclerlistview_1.ProgressiveListView).forEach(function (list, index) {
if (index === 0) {
expect(list.instance.getRenderedSize().width).toBe(400);
expect(list.instance.getRenderedSize().height).toBe(900);
}
else {
expect(list.instance.getRenderedSize().width).toBe(95);
expect(list.instance.getRenderedSize().height).toBe(900);
}
});
masonryFlashList.unmount();
});
it("divides columns equally if no getColumnFlex is passed", function () {
var masonryFlashList = (0, mountMasonryFlashList_1.mountMasonryFlashList)({
numColumns: 4,
});
var progressiveListView = masonryFlashList.find(recyclerlistview_1.ProgressiveListView).instance;
expect(progressiveListView.getLayout(0).width).toBe(100);
expect(progressiveListView.getLayout(1).width).toBe(100);
expect(progressiveListView.getLayout(2).width).toBe(100);
expect(progressiveListView.getLayout(3).width).toBe(100);
});
});
//# sourceMappingURL=MasonryFlashList.test.js.map
;