Nightwatch.js测试Vue Router加载的Vue单文件组件为何结果不一致?
我之前在项目里也碰到过几乎一模一样的情况——用Nightwatch测试Vue Router跳转后的SFC组件加载,总是出现断言时灵时不灵的问题,折腾了一阵后终于找到几个靠谱的解决办法,分享给你:
1. 一定要等Vue Router导航完全完成
路由跳转是异步的,Nightwatch默认同步执行命令,经常会在组件还没渲染完就跑去断言,结果自然不稳定。我当时写了个自定义命令专门等路由就绪:
在Nightwatch的commands目录下新建waitForRouterReady.js:
exports.command = function() { return this.executeAsync(function(done) { // 这里假设你的Vue实例挂载在window.app上,根据自己项目调整 window.app.$router.onReady(() => { done(true); }); }); };
然后在测试里这么用:
browser .click('router-link[to="/your-target-path"]') .waitForRouterReady() // 先等路由跳转和组件渲染完成 .assert.elementPresent('[data-testid="target-component"]');
如果是Vue 3的话,把$router.onReady换成$router.isReady()就行。
2. 给SFC加唯一的测试标识,用精准选择器
别用那种泛泛的类名来断言,比如.container这种可能到处都有的。给目标组件的根元素加个data-testid属性:
<!-- TargetComponent.vue --> <template> <div data-testid="target-component"> <!-- 组件内容 --> </div> </template>
然后断言的时候就用[data-testid="target-component"],这样完全不会和其他元素搞混,精准度高多了。
3. 别忽略Vue Material抽屉的潜在影响
虽然你觉得抽屉不是关键,但我当时排查发现,抽屉的关闭动画有时候会阻塞路由跳转的时机。后来我在点击router-link之前,先确保抽屉已经完全关闭:
browser .waitForElementNotVisible('.md-drawer--open', 3000) // 等抽屉关闭动画结束 .click('router-link[to="/your-target-path"]') .waitForRouterReady() .assert.elementPresent('[data-testid="target-component"]');
这个小调整居然解决了不少偶发的失败情况。
4. 用waitForElementPresent代替直接assert
Nightwatch的assert.elementPresent是单次检查,而waitForElementPresent会在指定超时时间内反复检查元素是否存在,容错性更强:
browser .click('router-link[to="/your-target-path"]') .waitForRouterReady() .waitForElementPresent('[data-testid="target-component"]', 5000); // 5秒内找到就通过
比直接断言靠谱多了,不会因为一两百毫秒的渲染延迟就失败。
5. 每次测试前重置状态
测试残留的Vuex状态或者路由状态也可能导致奇怪的问题,我会在每个测试的beforeEach里重置一下:
beforeEach(function(browser) { browser.execute(function() { // 重置Vuex状态为初始值 window.app.$store.replaceState({ // 你的初始状态对象 }); // 跳转到初始路由 window.app.$router.push('/'); }); });
把这些方法组合起来用,我这边的测试就再也没出现过断言不一致的情况了,你可以试试!
内容的提问来源于stack exchange,提问作者Kornatzky

