如何使用Jest正确测试Framer Motion动画执行后的组件样式?
解决方案
测试失败的核心原因是framer-motion的动画为异步调度,组件首次渲染完成时动画逻辑还未执行,因此DOM上的transform样式还未更新。以下是几种符合最佳实践的可行方案:
方案1:使用RTL的waitFor异步断言
这是改动最小的方案,不需要修改任何业务代码或全局配置,仅需调整测试逻辑,通过waitFor轮询断言条件,而非固定时长等待:
import { waitFor, screen, render } from '@testing-library/react'; test("Component when isSelected highlights the image", async () => { render(<Previewer isSelected />); const image = screen.getByRole("img"); await waitFor(() => { expect(image).toHaveStyle("transform: scale(1.5) translateZ(0)"); }); });
waitFor会在条件满足后立刻终止轮询,默认超时时间为1000ms,可通过第二个参数自定义超时配置,完全符合前端测试最佳实践。
方案2:测试环境全局Mock framer-motion
如果项目中有大量涉及framer-motion的测试用例,可以在测试环境全局配置Mock,让所有动画直接跳转到最终状态,无需等待,完全不影响生产环境的动画效果:
步骤1:配置jest全局Mock
在jest的setup文件(通常为jest.setup.js/jest.setup.ts)中添加如下代码:
jest.mock('framer-motion', () => { const original = jest.requireActual('framer-motion'); return { ...original, motion: new Proxy(original.motion, { get(target, key) { const originalComponent = target[key]; return (props) => originalComponent({ ...props, initial: false }); } }) }; });
这个Mock会给测试环境中所有的motion组件自动添加initial={false}属性,动画会立刻应用最终样式,你原来的同步测试代码不需要任何修改即可运行。
方案3:使用framer-motion官方测试Mock
framer-motion官方提供了专门用于测试的Mock包,不需要自己手写Mock逻辑,兼容性最好:
步骤1:修改jest配置
在jest.config.js中添加模块映射:
module.exports = { moduleNameMapper: { 'framer-motion': 'framer-motion/mock', }, }
配置完成后所有测试用例中的framer-motion动画都会直接应用最终状态,不需要额外的异步等待逻辑。
内容的提问来源于stack exchange,提问作者DLO
相关产品推荐
相关产品推荐

