如何用Enzyme和Jest测试React组件加载状态下显示Downloading...文本
问题概述
我有一个名为ChoiceOfFundForm的React组件,包含下载按钮。点击按钮会触发handleClick函数,将loading状态设为true并调用downloadChoiceOfFund动作;下载完成或出错后,loading会重置为false。
我需要编写测试用例,确保loading为true时,组件能通过DownloadingContainer正确显示...Downloading文本。使用Enzyme和Jest测试时,出现错误:TypeError: expect(...).text is not a function。
组件核心代码:
const DownloadingContainer = styled('div')({ color: 'rgb(92, 111, 123)', }); const ChoiceOfFundForm = ({ // props and state definitions }) => { // ... return ( <> <div style={{ display: 'flex', alignItems: 'center' }}> <ContributionFormLink // props onClick={handleClick} /> {loading && ( <DownloadingContainer data-testid="downloadingContainer"> ...Downloading </DownloadingContainer> )} </div> </> ); };
失败的测试代码:
jest.mock('react', () => ({ ...jest.requireActual('react'), useState: (initialState) => [initialState, mockSetLoading], })); it('should show "Downloading..." text when loading state is true', () => { mockSetLoading(true); const wrapper = shallow(<ChoiceOfFundForm store={store} />).dive(); const downloadingContainer = wrapper.find('[data-testid="downloadingContainer"]'); expect(downloadingContainer).text().toEqual('...Downloading'); });
错误原因
- 断言写法错误:
text()是Enzyme ShallowWrapper实例的方法,不能直接在expect()返回的断言对象上调用。正确顺序是先调用wrapper的text()获取内容,再传给expect()做断言。 - 状态模拟方式错误:直接调用
mockSetLoading(true)无法正确触发组件重新渲染,因为组件已经完成初始渲染,mock的useState不会自动更新组件状态。
解决方案
1. 修正断言写法
将错误的断言代码:
expect(downloadingContainer).text().toEqual('...Downloading');
改为:
expect(downloadingContainer.text()).toEqual('...Downloading');
2. 正确模拟loading状态
根据loading的来源(组件内部state或Redux store),选择对应的模拟方式:
情况1:loading是组件内部state
使用Enzyme的setState方法直接更新组件状态,并触发重新渲染:
it('should show "...Downloading" text when loading state is true', () => { const wrapper = shallow(<ChoiceOfFundForm store={store} />).dive(); // 设置组件内部loading为true wrapper.setState({ loading: true }); // 手动触发组件更新(部分Enzyme版本会自动更新,此步骤可选) wrapper.update(); const downloadingContainer = wrapper.find('[data-testid="downloadingContainer"]'); // 先验证元素存在 expect(downloadingContainer.exists()).toBe(true); // 验证文本内容 expect(downloadingContainer.text()).toEqual('...Downloading'); });
情况2:loading来自Redux store
初始化mockStore时传入loading: true的状态,确保组件渲染时能获取到正确的状态:
import configureMockStore from 'redux-mock-store'; const mockStore = configureMockStore(); // 初始化包含loading: true的store const store = mockStore({ // 其他必要的state字段 loading: true }); it('should show "...Downloading" text when loading state is true', () => { const wrapper = shallow(<ChoiceOfFundForm store={store} />).dive(); const downloadingContainer = wrapper.find('[data-testid="downloadingContainer"]'); expect(downloadingContainer.exists()).toBe(true); expect(downloadingContainer.text()).toEqual('...Downloading'); });
3. 移除不必要的useState mock
之前mock React useState的代码会干扰组件正常的状态管理,建议移除该mock,改用上述方式模拟状态。
完整修正后的测试示例(内部state场景)
import { shallow } from 'enzyme'; import ChoiceOfFundForm from './ChoiceOfFundForm'; it('should display "...Downloading" when loading is true', () => { const wrapper = shallow(<ChoiceOfFundForm store={store} />).dive(); // 更新loading状态 wrapper.setState({ loading: true }); wrapper.update(); const downloadingContainer = wrapper.find('[data-testid="downloadingContainer"]'); expect(downloadingContainer.exists()).toBe(true); expect(downloadingContainer.text().trim()).toEqual('...Downloading'); });
内容的提问来源于stack exchange,提问作者meWho
相关产品推荐
相关产品推荐

