我有/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
在服务器模式下运行测试,则相同的测试失败;但是,当我按输入重新运行测试时,所有测试都会通过。
失败消息始终相同,如下所示:
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: |
在所有测试运行后,测试会发出异常:
# 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的经验,但我至少会期望它给我一个错误 - 它实际上什么也没做。
在我的Ember应用程序中感觉好像phantomjs之间存在计时问题,可能是ember-simple-auth。
我不是经验丰富的调试phantomjs问题,也不是Ember验收测试失败,所以任何帮助都表示赞赏。
ember-cli 2.10.0
ember-simple-auth 1.1.0
ember-cli-mirage 0.2.4
该按钮位于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']);
});
}
}
});
根据丹尼尔的建议,我加入了延迟测试:
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毫秒。
我仍然想找到一个解释,因为我不相信这会在运行测试的任何机器上运行相同。
今天我有一个惊喜:突然间测试又恢复了!
我添加了一条带验收测试的新路线。路由本身是经过身份验证的路由,因此测试使用ember-simple-auth中的authenticateSession
测试帮助程序进行身份验证。
当我删除使用此帮助程序的测试时,错误会返回!。
我不确定这意味着什么。感觉就像问题是ember-simple-auth一样,但帮助者解决另一个时间问题可能也是一个巨大的巧合。
我们走下兔子洞......
以下是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'});
}
});
这是我的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;
};
答案 0 :(得分:1)
您可以在此处尝试调试此问题。
您可以从按钮中删除{{isDisabled}}
,以确保在您尝试单击它时未将其禁用。
使用setTimeout而不是andThen,看看它是否是时间问题。
用任何内容替换身份验证操作代码,以确保它不会导致测试失败。
您还可以重写测试,在JavaScript中的某些事件之后放置您的assert.ok。例如,您可以模拟验证操作或观察者错误属性。您可以通过在验收环境中使用查找或注册来执行此操作 - 来自我的一个Ember CLI插件的测试可以帮助您 - ember-link-action/tests/acceptance/link-action-test.js。
看到对你有用的经历告诉我你应该尝试两件事。
对于此代码:
andThen(function() {
Ember.run.later(this, function() {
assert.equal(find('div.notification').text(), "Invalid email/password");
}, 0);
});
您可以尝试Ember.run.scheduleOnce('afterRender', this, () => { ... assert here }
而不是Ember.run.later
。或者您可以尝试仅使用Ember.run
代替Ember.run.later
。
结论:解决此问题的关键可能是将您的断言置于Ember Run Loop中。
答案 1 :(得分:1)
我认为您看到的错误(Invalid email/password
)是(模拟)服务器响应,并指出您在测试中使用的模拟或凭据出现问题。
我也没有使用海市蜃楼来模拟身份验证请求。海市蜃楼(就像Jason API一样)是基于资源的,而不是非常适合身份验证的东西。