我正在尝试为模拟真实用户输入的ember组件编写测试。例如:
<div>
<input class='js-input' type='text' value='{{ bar }}'> </input>
<button class='js-save' type='submit' {{action 'save'}}>
</div>
我的组件目前使用change
和keyUp
事件根据输入的内容计算另一个值,并在运行中验证输入:
import Ember from 'ember';
export default Ember.Component.extend({
bar: null,
modelBar: null,
updateBar: Ember.on('change', 'keyUp', function() {
let bar = this.get('bar');
if (bar.get('notValid')) {
bar = null;
this.set('bar', '');
}
this.set('modelBar', bar);
}),
actions: {
save() {
... save stuff ...
}
}
});
所以我一直在使用$('.js-input').val('some new value')
来模拟这个(按照“与呈现的组件交互”中的推荐here)。
test('Updates a thing', function(assert) {
assert.expect(1);
const newState = 'a new state';
this.set('actions.save', (newTaxes) => {
assert.ok(true, 'save has been called');
assert.equal(newState, this.get('modelBar'), 'model is updated correctly');
});
this.set('bar', 'initial state');
this.render(hbs`
{{my-component
baz=baz
}}
`);
this.$('.js-input').val(newState);
this.$('.js-input').trigger('change');
this.$('.js-save').click();
});
但是,当我运行测试时,change
事件没有使用this.get('bar')
获取输入的更新值(尽管如果我使用this.$('js-input').val()
我可以看到它)。如果我添加一个观察者,我可以看到观察者获取该属性的更新值,但只有在自定义更改事件被触发后。
我已经尝试在Ember运行循环和run.next循环中包装东西,这也没有帮助。有没有办法让这项工作成功,希望不需要回到观察者身上? (该组件以前使用过观察者,但是一些新的要求使事情变得更加复杂。)
答案 0 :(得分:1)
根据您的舒适程度,我找到了几种方法来解决这个问题。不幸的是,它们都没有涉及到测试本身,所以我仍然很高兴听到有人有更好的解决方案。
一:修复问题jquery导致更多jquery:
updateBar: Ember.on('change', 'keyUp', function() {
... validate bar ...
this.set('modelBar', this.get('bar') || this.$('.js-input').val());
}),
我对此很好,因为它应仅用于测试目的。您可以担心bar
具有以前的值,但在我的情况下,它始终从空值变为值,因此||
是一个充分的指标。
二:回到观察者(叹气)。似乎虽然change
事件没有获得bar
的更新值,但是观察者会这样做,但只有在更改事件之后。
observerBar: Ember.observer('bar', function() {
if (!this.get('suspendObserver')) {
this.set('suspendObserver', true);
this.updateBar();
this.set('suspendObserver', false);
}
}),
在我的情况下,信号量是必要的,因为如果输入无效,updateBar将清除bar
。
答案 1 :(得分:1)
我相信它是因为bar
没有与<input>
元素捆绑在一起。因此,即使您致电this.$('.js-input').val(newState)
,bar
也不会改变。然后拨打this.$('.js-input').trigger('change')
会触发updateBar
,但不会获得预期的结果。
试试这个:
// template.hbs
<input class='js-input' type='text' value={{bar}} onchange={{action "handleChange" value="target.value"}}>
// component.js
actions: {
handleChange(value) {
// Your logic here -- value is the new value of your input
}
}