使用Ava测试图片加载Promise时,测试返回的Promise始终未解决
这种Promise一直挂起不resolve的情况,在使用browser-env模拟浏览器环境做测试时确实挺常见的,我帮你梳理几个核心排查方向:
1. 优先检查browser-env的初始化时机
browser-env需要在所有依赖导入(包括你的图片加载函数)之前执行,否则它无法正确模拟Image等浏览器全局对象。如果你的测试文件是先导入了加载函数再初始化browser-env,那Image构造函数可能已经拿到了Node.js环境下的空实现,自然不会触发事件。
正确的顺序应该是:
// 先初始化浏览器环境 require('browser-env')(); // 再导入你的函数和测试工具 const loadImage = require('./your-image-loader'); const test = require('ava');
如果你的项目有多个测试文件,也可以把browser-env的初始化放到Ava的setup文件中(在package.json的ava配置里指定setup字段),确保所有测试都能共享正确的环境。
2. 确认Image事件绑定与src设置的顺序
在真实浏览器或模拟环境中,如果先设置img.src再绑定onload/onerror,很可能因为图片缓存(模拟环境里也会有类似逻辑)导致事件已经触发,但你的监听函数还没绑定上,最终Promise永远无法resolve。
另外,一定要加上img.complete的检查——当图片已经在缓存中时,设置src不会触发onload,这时候需要手动触发resolve:
function loadImage(url) { return new Promise((resolve, reject) => { const img = new Image(); // 先绑定所有事件 img.onload = () => resolve(img); img.onerror = (err) => reject(new Error(`Failed to load image: ${url}`)); // 再设置src img.src = url; // 处理缓存命中的情况 if (img.complete) { resolve(img); } }); }
3. 调整Ava的测试超时时间
Ava的默认超时时间(通常是1000ms)可能不够应对模拟环境中的异步操作延迟,尤其是如果你的测试涉及到真实的图片加载请求。可以给测试用例单独设置更长的超时:
test('loads test image successfully', async t => { const img = await loadImage('https://via.placeholder.com/200'); t.is(img.width, 200); }, { timeout: 5000 }); // 设置5秒超时
4. 检查browser-env的模拟完整性
默认的browser-env模拟可能没有覆盖所有Image相关的属性或事件,你可以手动指定需要模拟的全局对象,确保Image的行为符合预期:
require('browser-env')(['window', 'Image', 'Event', 'HTMLElement']);
另外,要避免同时使用多个DOM模拟库(比如jsdom和browser-env),它们之间可能会冲突,导致Image的行为异常。
5. 验证测试图片的可用性
如果你的测试用的是本地图片,要确认路径是否正确(相对于测试文件的路径),或者直接用一个稳定的在线测试图片(比如https://via.placeholder.com/100)来排除本地文件的问题。在模拟环境中,Image可能不会真正发起网络请求,但如果路径错误,可能会触发onerror,但如果你的错误处理逻辑有问题,也可能导致Promise挂起。
先从前面两个方向排查,这是最常见的问题根源,应该能解决大部分情况。
内容的提问来源于stack exchange,提问作者TotomInc

