You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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 -

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 02:45:44