Ember 3.0采用RFC 268格式的验收重定向测试无限挂起
首先,咱们拆解下你遇到的核心问题:旧版moduleForAcceptance测试正常,但改用RFC268的setupApplicationTest+async/await后,测试卡在await visit()处无限挂起,控制台还没报错。这大概率是新测试模式和旧模式的行为差异导致的,咱们一步步分析解决。
可能遗漏的关键点
1. 路由钩子中的异步操作未正确收尾
Ember 3.0的新测试助手(比如visit)会严格等待所有异步操作完成(包括路由钩子中的Promise、数据加载等)才会resolve,而旧版andThen的等待逻辑没这么严格。如果你的受保护路由的beforeModel/afterModel钩子中有异步逻辑(比如session验证、异步数据请求),但没正确处理Promise的resolve,就会导致await visit()一直挂起。
举个反例,你的路由如果是这样写的:
// app/routes/protected.js import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; export default Route.extend({ session: service(), async beforeModel() { // 未await session异步加载,也没返回transitionTo的Promise if (!this.session.isAuthenticated) { this.transitionTo('login'); } } });
改成这样就能解决:
async beforeModel() { // 确保session的异步操作完成 await this.session.loadCurrentUser(); if (!this.session.isAuthenticated) { // 返回transitionTo的Promise,让测试感知重定向操作已完成 return this.transitionTo('login'); } }
2. 测试助手的导入不正确
确认你是从@ember/test-helpers导入visit、currentURL这些助手,而不是依赖旧版的全局助手。新测试模式下全局助手默认禁用,导入错误会导致行为异常:
// 正确导入方式 import { visit, currentURL } from '@ember/test-helpers';
3. 未检查应用中是否有未解决的全局Promise
如果你的应用初始化阶段(比如路由、服务)有一直pending的Promise,新测试的await visit()会一直等待所有异步任务settle。可以在浏览器控制台执行Ember.run.backburner.queues查看未处理任务,或者用pauseTest()调试:
test('visiting /protected redirects to /login', async function(assert) { await visit('/protected'); pauseTest(); // 在这里暂停,查看应用状态和未解决的Promise assert.equal(currentURL(), '/login'); });
更好的重定向测试方法
为了让测试更可靠、更快,建议模拟session的状态,而非依赖真实的session服务初始化。这样测试不需要等待真实异步请求,还能隔离外部依赖:
import { module, test } from 'qunit'; import { setupApplicationTest } from 'ember-qunit'; import { visit, currentURL } from '@ember/test-helpers'; module('Acceptance | unauthenticated redirect', function(hooks) { setupApplicationTest(hooks); test('unauthenticated user is redirected to /login', async function(assert) { // 直接模拟session未认证状态 let session = this.owner.lookup('service:session'); session.set('isAuthenticated', false); await visit('/protected'); assert.equal(currentURL(), '/login', '未认证用户被重定向到登录页'); }); test('authenticated user can access protected page', async function(assert) { // 模拟已认证状态,验证重定向逻辑不触发 let session = this.owner.lookup('service:session'); session.set('isAuthenticated', true); await visit('/protected'); assert.equal(currentURL(), '/protected', '已认证用户可访问受保护页面'); }); });
这种方式不仅能快速验证重定向逻辑,还能覆盖正反两种场景,测试更全面。
内容的提问来源于stack exchange,提问作者Will Haley

