React含useState与useEffect的自定义Hook测试失败,如何修复?
React含useState与useEffect的自定义Hook测试失败,如何修复?
我看了你的代码,发现几个导致测试失败的关键问题,咱们一步步拆解修复:
问题1:快照变量未实时更新
你在测试一开始就从result.current里解构出了step和externalCb:
const { step, externalCb } = result.current;
但这里的step只是初始状态的快照,当Hook内部通过setStep更新状态后,这个变量不会自动同步最新值。你后续断言的一直是这个旧的初始值,自然会失败。
解决办法:每次需要获取最新状态时,都直接从result.current中读取,不要提前解构缓存。
问题2:Cleanup字符串不匹配
你的Hook在组件卸载时,会把step设置为'cleanup',但测试里却断言它等于'cleaned',这是明显的字符串不一致,肯定会断言失败。
问题3:waitFor使用不正确
你传了一个空的waitFor(() => {}),这样它不会等待任何状态更新完成。正确的做法是在waitFor里传入需要验证的断言,让它等待状态更新后断言通过。
修改后的完整测试代码
import { act, renderHook } from '@testing-library/react-hooks'; import { expect } from 'chai'; describe('useCustomHook Hook', () => { it('step updates test', async () => { const { result, unmount, waitFor } = renderHook(() => useCustomHook('created')); // 初始状态断言:直接取最新的result.current.step expect(result.current.step).to.be.equal('created'); // 测试外部回调更新 act(() => { result.current.externalCb('updated'); }); // 等待状态更新完成并断言 await waitFor(() => { expect(result.current.step).to.be.equal('updated'); }); // 测试卸载时的cleanup act(() => { unmount(); }); await waitFor(() => { expect(result.current.step).to.be.equal('cleanup'); }); }); });
额外小提示
如果你需要重新渲染Hook并传入新的stepToSet参数,可以用renderHook的rerender方法,比如测试stepToSet变化时的更新逻辑:
it('updates step when stepToSet changes', async () => { const { result, rerender, waitFor } = renderHook((props) => useCustomHook(props.stepToSet), { initialProps: { stepToSet: 'initial' } }); expect(result.current.step).to.be.equal('initial'); // 传入新的props重新渲染 rerender({ stepToSet: 'changed' }); await waitFor(() => { expect(result.current.step).to.be.equal('changed'); }); });
这样修改后,你的测试应该就能正常通过了,核心就是要记住:result.current才是Hook返回值的实时引用,每次状态更新后都要从这里取最新值~
备注:内容来源于stack exchange,提问作者Dgurio
相关产品推荐
相关产品推荐

