如何使用Sinon在ReactJS中Mock Lottie模块导入解决单元测试报错
问题原因
你原有代码的Stub不生效的核心原因是ES模块的导入提升:当你在测试文件顶部
import LoadingOverlay from '../src/components/LoadingOverlay'时,组件内部已经完成了对真实lottie-react-web模块的导入和引用,后续你在测试用例中Stub的只是当前测试文件引入的Lottie对象,完全不会影响组件内部已经拿到的真实Lottie组件引用,所以canvas相关错误依然存在。
另外你代码还有两个潜在问题:
- 自定义的
FakeLottie直接返回<div>{props}</div>会报错,对象不能直接作为React子元素渲染 - 组件使用了
ConfigContext,测试时没有用Provider包裹传入值,会触发namespace未定义的错误
解决方案
推荐使用proxyquire做动态依赖替换,在加载组件前就替换掉lottie依赖:
步骤1:安装依赖
npm install proxyquire @types/proxyquire --save-dev
步骤2:修改测试代码
import React from 'react'; import { render } from '@testing-library/react'; import { expect } from 'chai'; import * as sinon from 'sinon'; import proxyquire from 'proxyquire'; import { ConfigContext } from '../src/ConfigProvider'; const TEST_ID = 'the-test-id'; // Mock Context值 const mockContextValue = { namespace: 'test' }; // 假Lottie组件 const FakeLottie = () => <div data-testid="fake-lottie"></div>; // 动态加载LoadingOverlay,直接替换它的lottie-react-web依赖 const { default: LoadingOverlay } = proxyquire( '../src/components/LoadingOverlay', { 'lottie-react-web': { default: FakeLottie } } ); describe('Loading Overlay', () => { it('should have a test ID', () => { const { getByTestId } = render( <ConfigContext.Provider value={mockContextValue}> <LoadingOverlay testId={TEST_ID} size="small" /> </ConfigContext.Provider> ); expect(getByTestId(TEST_ID)).to.exist; }); // 还可以扩展测试验证size参数生效 it('should pass correct size to Lottie', () => { const stubLottie = sinon.stub().returns(null); // 重新加载组件替换成带stub的Lottie const { default: SizeTestLoadingOverlay } = proxyquire( '../src/components/LoadingOverlay', { 'lottie-react-web': { default: stubLottie } } ); render( <ConfigContext.Provider value={mockContextValue}> <SizeTestLoadingOverlay size="large" /> </ConfigContext.Provider> ); expect(stubLottie.firstCall.args[0].height).to.equal('300px'); }); });
全局Mock方案(多测试文件复用)
如果多个测试文件都需要Mock lottie,可以用mock-require做全局替换:
- 安装依赖:
npm install mock-require --save-dev - 新建测试启动脚本
test/setup.js:
const mock = require('mock-require'); const React = require('react'); mock('lottie-react-web', () => React.createElement('div', { 'data-testid': 'fake-lottie' }));
- 启动mocha时指定加载启动脚本:
mocha --require test/setup.js 'test/**/*.test.tsx'
内容的提问来源于stack exchange,提问作者M_Zarnowski
相关产品推荐
相关产品推荐

