React测试报错TypeError: source.on is not a function求助
解决测试时的TypeError: source.on is not a function错误
核心问题
你的请求代码存在关键错误:创建FormData后,你没有直接将其作为请求体发送,而是把FormData里的字段提取到普通JavaScript对象data中。当这个对象包含File类型的image字段时,测试环境的MSW(Mock Service Worker)无法正确处理这种非标准请求体格式,从而抛出source.on is not a function错误。生产环境能运行只是依赖了浏览器或后端的兼容处理,但这并非正确实现方式。
修复请求代码
直接传递FormData作为请求体,同时移除手动设置的Content-Type头部(axios会自动为FormData生成带正确boundary的multipart/form-data头部):
images.forEach(async (image) => { const config = { headers: { 'Authorization': `Bearer ${user}` // 移除手动设置的Content-Type,axios会自动处理 } } const formData = new FormData(); formData.append('workId', JSON.stringify(workId)); formData.append('image', image.image, image.image.name); // 直接传递formData作为data参数,而非普通对象 await api.post(`${baseUrl}/work/api/images/create/`, formData, config) .then((r) => { console.log(`created successfully with status code ${r.status}`); }) .catch((e) => { console.error(`this is the error: ${e.response.status}`); }) })
调整测试代码
确保MSW的mock请求能正确处理标准的FormData格式,还可添加请求体验证逻辑:
it('should returns success on create images', async () => { server.use( http.post(`${baseUrl}/work/api/images/create/`, async ({ request }) => { // 可选:验证FormData内容是否符合预期 const formData = await request.formData(); expect(formData.get('workId')).toBe(JSON.stringify(1)); expect(formData.get('image')).toBeInstanceOf(File); return new HttpResponse(null, { status: 201 }) }), ) const user = userEvent.setup(); handerImagesWorkManager(1, 'user'); const images = [ new File(['text'], 'image-test.png', { type: 'image/png' }), new File(['text'], 'image-test2.png', { type: 'image/png' }), ]; const inputUpload: HTMLInputElement = screen.getByTestId(/upload_images/i); await user.upload(inputUpload, images); const spy = vi.spyOn(console, 'log'); const submitButton = await screen.findByDisplayValue(/upload all images/i); await user.click(submitButton); // 注意:forEach循环会发送多个请求,所以断言调用次数和内容 expect(spy).toHaveBeenCalledTimes(2); expect(spy).toHaveBeenCalledWith("created successfully with status code 201"); });
关键说明
- 手动设置
multipart/form-data头部会丢失boundary信息,这是multipart请求的必要组成部分,axios自动生成的头部才是标准格式。 - 直接发送FormData是符合multipart请求规范的写法,能同时兼容生产和测试环境。
- 测试中要注意,
forEach循环会触发多次请求,所以console.log会被调用多次,断言时需考虑这一点。
内容的提问来源于stack exchange,提问作者Guilherme Costa
相关产品推荐
相关产品推荐

