React Testing Library/Jest下DOM行为正确但测试用例失败如何解决
问题根因
你遇到的矛盾现象本质是测试执行时序和DOM更新时机不匹配,核心有3个问题:
- 你提前把
visits元素的查询结果存为了固定变量list,这个变量保存的是查询时刻的DOM快照(此时新增url的请求还没返回,只有3条数据),后续即使DOM更新为4条,这个变量的内容也不会刷新,所以断言永远拿到的是长度3的旧数组。 - 提交按钮点击后有两层异步逻辑:
axios.post提交短链、getUrls拉取最新列表,你没有等待这两个异步操作完成就直接查询DOM,拿到的自然是更新前的旧数据。 - 你在测试中直接调用了真实后端接口,测试结果完全依赖后端当前状态、网络情况,非常容易出现不稳定的情况。
- 日志里看到DOM有4条,是因为测试断言失败后,工具会打印失败时刻的最新DOM,此时两个异步请求刚好执行完成,DOM已经更新成了4条,和你断言时刻的状态不是同一个时间点的。
修复方案
第一步:Mock接口避免依赖真实后端
在测试文件顶部 mock axios,隔离外部依赖:
import axios from 'axios'; jest.mock('axios');
第二步:调整测试用例时序逻辑
修正后的测试用例如下:
test('URL list displays valid URL from input bar', async () => { // 模拟两次get请求的返回值:组件初始化返回3条,提交后返回4条 const mockOldUrls = [ {urlId:1, shortUrl:'http://www.baseUrl.com/123', urlName:'test1', visits:2}, {urlId:2, shortUrl:'http://www.baseUrl.com/456', urlName:'test2', visits:1}, {urlId:3, shortUrl:'http://www.baseUrl.com/789', urlName:'test3', visits:5}, ]; const mockNewUrls = [...mockOldUrls, { urlId:4, shortUrl:'http://www.baseUrl.com/shorten/123', urlName:'test4', visits:9 }]; axios.get.mockResolvedValueOnce({data: mockOldUrls}); // 组件初始加载请求 axios.post.mockResolvedValueOnce({}); // 提交短链请求 axios.get.mockResolvedValueOnce({data: mockNewUrls}); // 提交后拉取最新列表请求 const passingText = 'http://www.google.com'; const testText = 'test4'; render(<UrlShortener />); const urlInput = screen.getByPlaceholderText('Enter URL here...'); const nameInput = screen.getByPlaceholderText('Name your URL...'); const submitBtn = screen.getByRole('button', { name: 'Shorten!' }); // userEvent所有交互都是异步,必须加await await userEvent.type(urlInput, passingText); await userEvent.type(nameInput, testText); await userEvent.click(submitBtn); const listButton = screen.getByText('Link History'); await userEvent.click(listButton); // 先等待新增的test4出现在DOM中,确认列表已经更新完成 await screen.findByText('test4'); // 此时再查询visits元素断言长度 const list = screen.getAllByText(/visits/i); expect(list).toHaveLength(4); });
内容的提问来源于stack exchange,提问作者Adam Mann
相关产品推荐
相关产品推荐

