React图片上传组件尺寸验证测试失败问题求助
React图片上传组件尺寸验证测试失败解决指南
问题描述
我在React中实现了图片上传组件,包含三类前端验证:
- 文件为图片格式
- 文件大小不超过X KB
- 文件宽高需小于1024px × 1024px
前两类验证的测试已通过,但第三类尺寸验证测试始终失败。测试时加载了项目内的真实图片,却无法获取正确尺寸;但实际上传不符合要求的图片时,所有验证(包括尺寸验证)都能正常生效。
测试代码如下:
describe('Image field validation', () => { test('Submitting an image with invalid format should display a format error message', async () => { await renderWithApiContextStack( <Router> <CategoriesContextProvider> <CategoryForm mode={FormMode.ADD} /> </CategoriesContextProvider> </Router> ); await displayAllFormFields(); const categoryImageField = await screen.findByLabelText('Browse your file'); expect(categoryImageField).toBeInTheDocument(); const file = new File(['(⌐□_□)'], 'image.bmp', { type: 'image/bmp' }); fireEvent.change(categoryImageField, { target: { files: [file] } }); expect( await screen.findByText( enGB.translation.components.customInputs.imageUpload.errors.invalidFormat ) ).toBeInTheDocument(); }); test('Submitting an image with invalid dimensions (width * height) should display a dimensions error message', async () => { await renderWithApiContextStack( <Router> <CategoriesContextProvider> <CategoryForm mode={FormMode.ADD} /> </CategoriesContextProvider> </Router> ); await displayAllFormFields(); const categoryImageField = await screen.findByLabelText('Browse your file'); expect(categoryImageField).toBeInTheDocument(); const imagePath = path.resolve(__dirname, '../../../__mocks__/images/big_image.png'); const imageBuffer = fs.readFileSync(imagePath); const imageFile = new File([imageBuffer], 'big_image.png', { type: 'image/png', }); console.log(imageFile) fireEvent.change(categoryImageField, { target: { files: [imageFile] } }); expect( await screen.findByText( enGB.translation.components.customInputs.imageUpload.errors.maxDimensionsSize ) ).toBeInTheDocument(); }); test('Submitting a big image in size with should display a max size (MB) error message', async () => { await renderWithApiContextStack( <Router> <CategoriesContextProvider> <CategoryForm mode={FormMode.ADD} /> </CategoriesContextProvider> </Router> ); await displayAllFormFields(); const categoryImageField = await screen.findByLabelText('Browse your file'); expect(categoryImageField).toBeInTheDocument(); const file = new File([''], 'test_img.png', { type: 'image/png' }); Object.defineProperty(file, 'size', { value: 1024 * 1024 }); fireEvent.change(categoryImageField, { target: { files: [file] } }); expect( await screen.findByText( enGB.translation.components.customInputs.imageUpload.errors.maxFileSize ) ).toBeInTheDocument(); }); });
问题核心
测试环境(如Jest)不会像真实浏览器那样自动解析图片文件的元数据。真实浏览器中,组件通过创建Image对象加载文件来获取宽高,但测试环境没有模拟这一异步解析过程,导致尺寸验证逻辑无法拿到有效宽高值。
解决方案
方案1:Mock Image构造函数
在测试文件顶部全局mockImage类,模拟大尺寸图片的宽高及加载完成回调:
global.Image = class { constructor() { // 设置不符合要求的宽高 this.width = 2048; this.height = 2048; // 立即触发onload回调,模拟图片加载完成 setTimeout(() => this.onload?.(), 0); } }; // 原测试逻辑保持不变 test('Submitting an image with invalid dimensions (width * height) should display a dimensions error message', async () => { // ... 原有代码 });
方案2:手动解析图片尺寸(需依赖canvas)
安装canvas包后,在测试中手动解析图片真实宽高,再注入到验证逻辑中:
npm install canvas --save-dev
测试代码修改:
import { createCanvas, Image } from 'canvas'; import fs from 'fs'; import path from 'path'; // 解析图片宽高的工具函数 const getImageDimensions = (buffer) => { return new Promise((resolve) => { const img = new Image(); img.onload = () => resolve({ width: img.width, height: img.height }); img.src = buffer; }); }; test('Submitting an image with invalid dimensions...', async () => { await renderWithApiContextStack( <Router> <CategoriesContextProvider> <CategoryForm mode={FormMode.ADD} /> </CategoriesContextProvider> </Router> ); await displayAllFormFields(); const categoryImageField = await screen.findByLabelText('Browse your file'); const imagePath = path.resolve(__dirname, '../../../__mocks__/images/big_image.png'); const imageBuffer = fs.readFileSync(imagePath); const { width, height } = await getImageDimensions(imageBuffer); // 如果组件验证逻辑支持传入尺寸参数,可在此处注入;或mock组件内获取尺寸的方法 const imageFile = new File([imageBuffer], 'big_image.png', { type: 'image/png' }); fireEvent.change(categoryImageField, { target: { files: [imageFile] } }); expect(await screen.findByText(enGB.translation.components.customInputs.imageUpload.errors.maxDimensionsSize)).toBeInTheDocument(); });
方案3:修改组件验证逻辑适配测试
在组件的尺寸验证逻辑中增加测试环境判断,允许通过自定义参数传入宽高,避免依赖真实图片解析:
// 组件内的尺寸验证函数 const validateImageDimensions = async (file, testDimensions) => { if (process.env.NODE_ENV === 'test' && testDimensions) { const { width, height } = testDimensions; return width <= 1024 && height <= 1024; } // 真实环境下的解析逻辑 return new Promise((resolve) => { const img = new Image(); img.onload = () => resolve(img.width <= 1024 && img.height <= 1024); img.src = URL.createObjectURL(file); }); };
关键注意点
- 尺寸验证逻辑通常是异步的,必须确保mock的
Image对象正确触发onload回调,否则测试会因等待超时失败。 - 若使用
canvas解析图片,需确保测试环境支持该依赖,部分CI环境可能需要额外配置。
内容的提问来源于stack exchange,提问作者Albert Lazaro de Lara
相关产品推荐
相关产品推荐

