Jest测试React Native FlatList时onViewableItemsChanged内部代码未执行
React Native FlatList onViewableItemsChanged 单元测试内部语句未执行问题解决
在React Native中使用FlatList的onViewableItemsChanged属性时功能运行正常,但单元测试中发现该函数虽被调用,内部语句却未执行。以下是相关代码:
app.js
const onViewableItemsChanged = React.useCallback( ({ viewableItems, changed, viewabilityConfig }) => { setActiveIndex(viewableItems); }, [], ); const setActiveIndex = (activeViews) => { if (activeViews?.length !== 0) { let index = activeViews[0]?.index; setActiveViewIndex(index); } }; return( <View> <View> <FlatList data={checkedInPersonsList} horizontal showsHorizontalScrollIndicator={false} style={{ flexGrow: 0 }} contentContainerStyle={{ paddingHorizontal: containerHorizontalPadding, }} renderItem={({ item, index }) => renderFlatList(item, index, checkedInPersonsList) } onViewableItemsChanged={onViewableItemsChanged} viewabilityConfig={{ itemVisiblePercentThreshold: 92, }} ItemSeparatorComponent={() => ( <View style={{ paddingHorizontal: 10 }} /> )} testID={'PaxScrollerFlatList.test'} /> </View> </View> )
app.test.js
import React from 'react'; import { render, fireEvent } from '@testing-library/react-native'; import PaxScroller from './index'; describe('Pax Scroller', () => { test('Scroll Flatlist Horizontal', () => { const { getAllByTestId, getByTestId } = render( <PaxScroller checkedInPersonsList={list} />, ); let fList = getByTestId('PaxScrollerFlatList.test'); fireEvent.scroll(fList, { nativeEvent: { contentSize: { height: 600, width: 600 }, contentOffset: { y: 0, x: 0 }, layoutMeasurement: { height: 100, width: 400 }, }, }); }); }
测试执行后,覆盖率显示onViewableItemsChanged已被调用,但内部的setActiveIndex及后续语句未执行,以下是解决方法:
解决方法
1. 直接模拟onViewableItemsChanged调用
测试环境中触发scroll事件时,不会像真实设备那样精确计算可见项比例,导致传入的viewableItems为空数组。直接调用FlatList的onViewableItemsChanged并构造符合条件的参数,能确保内部逻辑执行:
test('Scroll updates active index', () => { const { getByTestId } = render( <PaxScroller checkedInPersonsList={list} />, ); const fList = getByTestId('PaxScrollerFlatList.test'); // 传入包含可见项的参数,模拟第一个项被识别为可见 fList.props.onViewableItemsChanged({ viewableItems: [{ index: 0 }], changed: [], viewabilityConfig: { itemVisiblePercentThreshold: 92 } }); // 此处添加断言,比如验证setActiveViewIndex是否被正确调用 // 示例:若使用jest.mock跟踪状态更新,可断言setActiveViewIndex被调用一次,参数为0 });
2. 调整scroll事件参数匹配可见阈值
你的viewabilityConfig要求项可见比例≥92%,需调整scroll事件的参数,确保某个项的可见比例达标:
import { waitFor } from '@testing-library/react-native'; test('Scroll triggers viewable item logic', async () => { const { getByTestId } = render( <PaxScroller checkedInPersonsList={list} />, ); const fList = getByTestId('PaxScrollerFlatList.test'); // 假设每个项宽度100px,容器宽度刚好显示一个项,确保可见比例超过92% fireEvent.scroll(fList, { nativeEvent: { contentSize: { height: 100, width: list.length * 110 }, // 项+分隔符总宽度 contentOffset: { y: 0, x: 0 }, layoutMeasurement: { height: 100, width: 100 }, }, }); // 等待状态异步更新完成 await waitFor(() => { // 添加UI断言,比如检查active状态的元素是否存在 }); });
3. 跟踪状态更新并验证
若组件通过setActiveViewIndex更新状态,可通过测试库查询方法验证状态变化:
test('Active index updates on scroll', async () => { const { getByTestId, getByText } = render( <PaxScroller checkedInPersonsList={list} />, ); const fList = getByTestId('PaxScrollerFlatList.test'); fList.props.onViewableItemsChanged({ viewableItems: [{ index: 1 }], changed: [], viewabilityConfig: {} }); await waitFor(() => { // 假设active项会显示"当前选中"文本,验证该元素存在 expect(getByText('当前选中')).toBeTruthy(); }); });
关键原因
测试模拟的scroll事件不会像真实设备那样精确计算可见项比例,导致viewableItems为空数组,跳过了setActiveIndex中的条件判断。直接构造参数调用目标函数,能强制触发内部逻辑。
内容的提问来源于stack exchange,提问作者Shariq Ahmed -
相关产品推荐
相关产品推荐

