【发布时间】:2016-12-10 14:26:18
【问题描述】:
问题
我有一个/login 路由,它使用ember-simple-auth 来实现身份验证。在测试期间,ember-cli-mirage 用于模拟后端。用户通过提供他们的电子邮件地址和密码登录。
对于这条路线,我总共有 4 次验收测试,类似于下面的测试:
test('should show error message for invalid email', function(assert) {
visit('/login');
fillIn('input#email', 'invalid-email');
fillIn('input#password', 'invalid-password');
click('button.button');
andThen(function() {
assert.equal(find('div.notification').text(), "Invalid email/password");
});
});
当我使用ember t 运行测试时,只有文件中的第一个测试失败。如果我将此测试注释掉,则下一个测试会失败,依此类推。如果我使用ember t -s 在服务器模式下运行测试,同样的测试会失败;但是,当我按 enter 重新运行测试时,所有测试都通过了。
失败信息总是一样的,如下图:
not ok 7 PhantomJS 2.1 - Acceptance | login: should show error message for invalid email
---
actual: >
expected: >
Invalid email/password
stack: >
http://localhost:7357/assets/tests.js:22:19
andThen@http://localhost:7357/assets/vendor.js:48231:41
http://localhost:7357/assets/vendor.js:48174:24
isolate@http://localhost:7357/assets/vendor.js:49302:30
http://localhost:7357/assets/vendor.js:49258:23
tryCatch@http://localhost:7357/assets/vendor.js:68726:20
invokeCallback@http://localhost:7357/assets/vendor.js:68738:21
publish@http://localhost:7357/assets/vendor.js:68709:21
http://localhost:7357/assets/vendor.js:48192:24
invoke@http://localhost:7357/assets/vendor.js:10892:18
flush@http://localhost:7357/assets/vendor.js:10960:15
flush@http://localhost:7357/assets/vendor.js:11084:20
end@http://localhost:7357/assets/vendor.js:11154:28
run@http://localhost:7357/assets/vendor.js:11277:19
run@http://localhost:7357/assets/vendor.js:32073:32
http://localhost:7357/assets/vendor.js:48783:24
Log: |
在所有测试都运行之后,test 会发出一个异常:
# tests 60
# pass 59
# skip 0
# fail 1
Not all tests passed.
Error: Not all tests passed.
at EventEmitter.getExitCode (/home/jon/projects/jonblack/wishlist-web/node_modules/testem/lib/app.js:434:15)
at EventEmitter.exit (/home/jon/projects/jonblack/wishlist-web/node_modules/testem/lib/app.js:189:23)
at /home/jon/projects/jonblack/wishlist-web/node_modules/testem/lib/app.js:103:14
at tryCatcher (/home/jon/projects/jonblack/wishlist-web/node_modules/testem/node_modules/bluebird/js/release/util.js:16:23)
at Promise._settlePromiseFromHandler (/home/jon/projects/jonblack/wishlist-web/node_modules/testem/node_modules/bluebird/js/release/promise.js:510:31)
at Promise._settlePromise (/home/jon/projects/jonblack/wishlist-web/node_modules/testem/node_modules/bluebird/js/release/promise.js:567:18)
at Promise._settlePromise0 (/home/jon/projects/jonblack/wishlist-web/node_modules/testem/node_modules/bluebird/js/release/promise.js:612:10)
at Promise._settlePromises (/home/jon/projects/jonblack/wishlist-web/node_modules/testem/node_modules/bluebird/js/release/promise.js:691:18)
at Async._drainQueue (/home/jon/projects/jonblack/wishlist-web/node_modules/testem/node_modules/bluebird/js/release/async.js:138:16)
at Async._drainQueues (/home/jon/projects/jonblack/wishlist-web/node_modules/testem/node_modules/bluebird/js/release/async.js:148:10)
at Immediate.Async.drainQueues (/home/jon/projects/jonblack/wishlist-web/node_modules/testem/node_modules/bluebird/js/release/async.js:17:14)
at runCallback (timers.js:637:20)
at tryOnImmediate (timers.js:610:5)
at processImmediate [as _immediateCallback] (timers.js:582:5)
这似乎很奇怪,因为测试失败而不仅仅是报告测试失败,所以它可能是相关的。
在 Firefox 和 Chromium 中运行测试可以正常工作,就像在开发模式下运行应用程序并手动登录一样。问题仅限于phantomjs。
我对另一条路线进行了其他验收测试,这些都通过了。似乎仅限于/login路由,说明可能与身份验证有关。
调试
我尝试通过将pauseTest() 添加到测试并将"phantomjs_debug_port": 9000 添加到testem.js 进行调试,但是当我使用调试控制台时,Firefox 和 Chromium 都没有执行任何操作。这可能是我缺乏调试 phantomjs 的经验,但我至少希望它会给我一个错误 - 它实际上什么也没做。
感觉好像 phantomjs 和我的 Ember 应用程序中可能的 ember-simple-auth 之间存在时间问题。
我对调试 phantomjs 问题或 Ember 验收测试失败的经验并不多,因此感谢您提供任何帮助。
版本
ember-cli 2.10.0
ember-simple-auth 1.1.0
ember-cli-mirage 0.2.4
更新 1
按钮位于login-form 组件内:
<form {{action 'login' on='submit'}}>
<p class="control has-icon">
{{input value=email id='email' placeholder='email' class='input'}}
<i class="fa fa-envelope"></i>
</p>
<p class="control has-icon">
{{input value=password id='password' placeholder='password'
type='password' class='input'}}
<i class="fa fa-lock"></i>
</p>
<p class="control">
<button class="button is-success" disabled={{isDisabled}}>Log In</button>
</p>
</form>
组件的登录操作只是调用传入的登录处理程序:
import Ember from 'ember';
export default Ember.Component.extend({
email: "",
password: "",
isDisabled: Ember.computed('email', 'password', function() {
return this.get('email') === "" || this.get('password') === "";
}),
actions: {
login() {
var email = this.get('email');
var password = this.get('password');
this.attrs.login(email, password);
}
}
});
哪个是登录控制器中的authenticate方法:
import Ember from 'ember';
export default Ember.Controller.extend({
session: Ember.inject.service(),
actions: {
authenticate(email, password) {
this.get('session').authenticate('authenticator:oauth2', email, password).catch((data) => {
this.set('errors', data['errors']);
});
}
}
});
更新 2
按照 Daniel 的建议,我在测试中添加了延迟:
test('should show error message for invalid email', function(assert) {
visit('/login');
fillIn('input#email', 'invalid-email');
fillIn('input#password', 'invalid-password');
click('button.button');
andThen(function() {
Ember.run.later(this, function() {
assert.equal(find('div.notification').text(), "Invalid email/password");
}, 0);
});
});
仅使用 Ember.run.later 测试仍然失败,但将其放入 andThen 会使其通过。你注意到奇怪的部分了吗? 延迟为 0 毫秒。
我仍然想为此找到一个解释,因为我不相信这会在运行测试的任何机器上运行相同。
更新 3
今天我有一个惊喜:突然测试又开始了!
我添加了一条带有验收测试的新路线。路由本身是经过身份验证的路由,因此测试使用来自 ember-simple-auth 的 authenticateSession 测试助手进行身份验证。
当我删除使用此帮助程序的测试时,错误返回!。
我不确定这意味着什么。感觉问题出在 ember-simple-auth 上,但助手解决另一个时间问题也可能是一个巨大的巧合。
我们去兔子洞……
更新 4
下面是 ember-cli-mirage 中 auth 端点的配置:
this.post('/token', function({db}, request) {
var data = parsePostData(request.requestBody);
if (data.grant_type === 'password') {
// Lookup user in the mirage db
var users = db.users.where({ email: data.username });
if (users.length !== 1) {
return new Mirage.Response(400, {'Content-Type': 'application/json'}, {
errors: [{
id: 'invalid_login',
status: '400',
title: 'Invalid email/password',
}]
});
}
var user = users[0];
// Check password
if (data.password === user.password) {
if (!user.active) {
return new Mirage.Response(400, {'Content-Type': 'application/json'}, {
errors: [{
id: 'inactive_user',
status: '400',
title: 'Inactive user',
}]
});
} else {
return new Mirage.Response(200, {
'Content-Type': 'application/json'
}, {
access_token: 'secret token!',
user_id: user.id
});
}
} else {
return new Mirage.Response(400, {'Content-Type': 'application/json'}, {
errors: [{
id: 'invalid_login',
status: '400',
title: 'Invalid email/password',
}]
});
}
} else {
return new Mirage.Response(400, {'Content-Type': 'application/json'}, {
errors: [{
id: 'invalid_grant_type',
status: '400',
title: 'Invalid grant type',
}]
});
}
});
this.post('/revoke', function(db, request) {
var data = parsePostData(request.requestBody);
if (data.token_type_hint === 'access_token' ||
data.token_type_hint === 'refresh_token') {
return new Mirage.Response(200, {'Content-Type': 'application/json'});
} else {
return new Mirage.Response(400, {'Content-Type': 'application/json'},
{error: 'unsupported_token_type'});
}
});
更新 5
这是我的config/environment.js 文件:
/* jshint node: true */
module.exports = function(environment) {
var ENV = {
modulePrefix: 'wishlist-web',
environment: environment,
rootURL: '/',
locationType: 'auto',
EmberENV: {
FEATURES: {
},
EXTEND_PROTOTYPES: {
// Prevent Ember Data from overriding Date.parse.
Date: false
}
},
APP: {
}
};
if (environment === 'development') {
}
if (environment === 'test') {
// Testem prefers this...
ENV.locationType = 'none';
// keep test console output quieter
ENV.APP.LOG_ACTIVE_GENERATION = false;
ENV.APP.LOG_VIEW_LOOKUPS = false;
ENV.APP.rootElement = '#ember-testing';
}
if (environment === 'production') {
ENV.ServerTokenEndpoint = 'http://localhost:9292/token';
ENV.ServerTokenRevocationEndpoint = 'http://localhost:9292/revoke';
ENV.ApiHost = 'http://localhost:9292';
}
return ENV;
};
【问题讨论】:
-
当你点击
button.button时,你如何创建一个promise?你能提供创建承诺的代码吗? (我的猜测是在 phantomjs 环境中无法解决 promise。)
标签: ember.js phantomjs ember-simple-auth