lottie-react-native单元测试高级技巧:模拟动画加载与事件
lottie-react-native单元测试高级技巧:模拟动画加载与事件
【免费下载链接】lottie-react-native 项目地址: https://gitcode.com/gh_mirrors/lot/lottie-react-native
你是否还在为动画组件的单元测试头疼?本文将系统讲解如何解决lottie-react-native测试中的三大痛点:动画加载超时、事件回调验证、跨平台兼容性测试,帮助你构建稳定可靠的动画测试体系。读完本文你将掌握:使用Jest模拟本地/远程动画资源、验证onAnimationFinish等关键事件、编写跨平台兼容的测试用例。
测试环境准备
核心依赖配置
lottie-react-native的测试需要配置React Native测试环境并安装必要依赖:
# 安装测试依赖
npm install --save-dev jest react-test-renderer @testing-library/react-native
关键文件结构
测试相关的核心源码文件路径:
- 类型定义:packages/core/src/types.ts - 包含LottieViewProps接口定义
- 组件实现:packages/core/src/LottieView/index.tsx - LottieView组件核心实现
- 示例代码:example/App.tsx - 提供动画加载与控制的参考实现
模拟动画资源加载
本地JSON动画模拟
使用Jest的jest.mock模拟本地JSON动画文件,避免真实文件读取:
// 模拟本地动画文件
jest.mock('../animations/LottieLogo1.json', () => ({
v: '5.5.7',
fr: 30,
ip: 0,
op: 60,
w: 300,
h: 300,
layers: []
}), { virtual: true });
// 测试组件中使用
import LottieLogo1 from '../animations/LottieLogo1.json';
test('renders local animation', () => {
const { getByTestId } = render(<LottieView source={LottieLogo1} testID="local-animation" />);
expect(getByTestId('local-animation')).toBeTruthy();
});
远程URI动画模拟
使用jest.mock结合jest.fn模拟LottieView组件,拦截远程资源加载:
// 模拟LottieView组件
jest.mock('lottie-react-native', () => ({
__esModule: true,
default: jest.fn(({ source, onAnimationLoaded }) => {
// 模拟远程加载完成
if (source?.uri && onAnimationLoaded) {
setTimeout(onAnimationLoaded, 0);
}
return <View testID="mock-lottie" />;
})
}));
test('handles remote animation loading', async () => {
const onLoaded = jest.fn();
render(<LottieView source={{ uri: 'https://example.com/anim.json' }} onAnimationLoaded={onLoaded} />);
// 验证加载完成回调被调用
await waitFor(() => {
expect(onLoaded).toHaveBeenCalled();
});
});
.lottie格式文件处理
针对二进制.lottie格式文件,使用jest.mock直接返回模拟对象:
// 模拟.lottie文件
jest.mock('../animations/animation_lkekfrcl.lottie', () => 'mock-lottie-file', { virtual: true });
test('renders dotLottie animation', () => {
const { getByTestId } = render(
<LottieView source={require('../animations/animation_lkekfrcl.lottie')} testID="dotlottie-animation" />
);
expect(getByTestId('dotlottie-animation')).toBeTruthy();
});
事件回调测试策略
onAnimationFinish事件验证
通过模拟动画完成事件,验证回调函数行为:
test('triggers onAnimationFinish when loop is false', async () => {
const finishCallback = jest.fn();
render(
<LottieView
source={LottieLogo1}
loop={false}
autoPlay={true}
onAnimationFinish={finishCallback}
testID="finish-test"
/>
);
// 等待动画完成回调
await waitFor(() => {
expect(finishCallback).toHaveBeenCalledWith(false); // isCancelled=false
});
});
onAnimationFailure错误处理
模拟资源加载失败场景,测试错误处理逻辑:
test('handles animation loading failure', async () => {
const errorCallback = jest.fn();
// 模拟加载失败的LottieView
jest.mock('lottie-react-native', () => ({
__esModule: true,
default: jest.fn(({ onAnimationFailure }) => {
// 立即触发错误回调
setTimeout(() => onAnimationFailure?.('Failed to load'), 0);
return <View testID="failing-lottie" />;
})
}));
render(
<LottieView
source={{ uri: 'invalid-url' }}
onAnimationFailure={errorCallback}
/>
);
await waitFor(() => {
expect(errorCallback).toHaveBeenCalledWith('Failed to load');
});
});
事件流程测试
使用 Jest 的 mock 函数跟踪完整事件流程:
test('complete animation event flow', async () => {
const loadCallback = jest.fn();
const finishCallback = jest.fn();
render(
<LottieView
source={LottieLogo1}
loop={false}
autoPlay={true}
onAnimationLoaded={loadCallback}
onAnimationFinish={finishCallback}
/>
);
// 验证事件触发顺序
await waitFor(() => {
expect(loadCallback).toHaveBeenCalledTimes(1);
});
await waitFor(() => {
expect(finishCallback).toHaveBeenCalledWith(false);
});
// 确保加载先于完成
expect(loadCallback.mock.invocationCallOrder[0]).toBeLessThan(
finishCallback.mock.invocationCallOrder[0]
);
});
跨平台测试注意事项
平台特定属性处理
针对不同平台的特有属性,使用Platform.select在测试中区分处理:
import { Platform } from 'react-native';
test('applies platform-specific props', () => {
const mockLottie = jest.fn();
jest.mock('lottie-react-native', () => ({
__esModule: true,
default: mockLottie
}));
render(<LottieView
enableMergePathsAndroidForKitKatAndAbove={true}
useNativeLooping={Platform.OS === 'windows'}
/>);
if (Platform.OS === 'android') {
expect(mockLottie).toHaveBeenCalledWith(
expect.objectContaining({
enableMergePathsAndroidForKitKatAndAbove: true
}),
expect.anything()
);
}
});
渲染模式测试
验证不同渲染模式(AUTOMATIC/HARDWARE/SOFTWARE)的属性传递:
test('sets render mode correctly', () => {
const { rerender } = render(<LottieView renderMode="HARDWARE" testID="lottie-render" />);
expect(getByTestId('lottie-render').props.renderMode).toBe('HARDWARE');
// 测试模式切换
rerender(<LottieView renderMode="SOFTWARE" testID="lottie-render" />);
expect(getByTestId('lottie-render').props.renderMode).toBe('SOFTWARE');
});
高级测试场景
进度控制测试
模拟进度值变化,验证动画状态更新:
test('controls animation progress', () => {
const { rerender } = render(<LottieView source={LottieLogo1} progress={0} testID="progress-test" />);
// 更新进度值
rerender(<LottieView source={LottieLogo1} progress={0.5} testID="progress-test" />);
expect(getByTestId('progress-test').props.progress).toBe(0.5);
rerender(<LottieView source={LottieLogo1} progress={1} testID="progress-test" />);
expect(getByTestId('progress-test').props.progress).toBe(1);
});
颜色滤镜测试
验证颜色滤镜属性正确应用:
test('applies color filters', () => {
const colorFilters = [
{ keypath: 'layer1', color: '#ff0000' }
];
const { getByTestId } = render(
<LottieView
source={LottieLogo1}
colorFilters={colorFilters}
testID="color-filter-test"
/>
);
expect(getByTestId('color-filter-test').props.colorFilters).toEqual(
colorFilters.map(filter => ({
...filter,
color: processColor(filter.color) // 验证颜色值被处理
}))
);
});
测试工具与最佳实践
测试工具链
推荐使用以下工具组合提升测试效率:
- 组件测试:
@testing-library/react-native- 提供直观的组件查询和交互API - 异步测试:
jest.useFakeTimers()结合waitFor- 处理动画异步事件 - 代码覆盖率:
jest --coverage- 确保测试覆盖关键逻辑路径
常见问题解决方案
| 问题场景 | 解决方法 |
|---|---|
| 动画加载超时 | 使用jest.setTimeout增加超时时间,或直接模拟加载完成 |
| 事件不触发 | 确保loop={false}时测试onAnimationFinish,避免循环动画无法结束 |
| 跨平台差异 | 使用Platform.OS条件测试,分别验证各平台特有属性 |
性能优化建议
- 减少渲染次数:使用
jest.mock替代真实组件渲染 - 并行测试:通过
jest --maxWorkers=4启用多线程测试 - 选择性测试:使用
test.only和test.skip聚焦关键测试用例
总结
通过本文介绍的测试技巧,你可以:
- 使用Jest模拟各种动画资源(本地JSON、远程URI、.lottie格式)
- 验证关键事件回调(加载完成、播放结束、错误处理)
- 处理跨平台差异和特殊渲染模式
- 编写高效可靠的动画组件测试用例
官方文档:docs/api.md 提供了完整的API参考,建议结合测试实践深入学习。通过系统化的单元测试,可以显著提升动画功能的稳定性和开发效率。
掌握这些技巧,让你的动画组件测试不再依赖真实设备和网络环境,实现快速、可靠的测试流程!
【免费下载链接】lottie-react-native 项目地址: https://gitcode.com/gh_mirrors/lot/lottie-react-native
更多推荐


所有评论(0)