在Ember组件测试中模拟用户输入

时间:2016-07-19 16:19:04

标签: jquery ember.js qunit

我正在尝试为模拟真实用户输入的ember组件编写测试。例如:

<div>
  <input class='js-input' type='text' value='{{ bar }}'> </input>
  <button class='js-save' type='submit' {{action 'save'}}>
</div>

我的组件目前使用changekeyUp事件根据输入的内容计算另一个值,并在运行中验证输入:

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循环中包装东西,这也没有帮助。有没有办法让这项工作成功,希望不需要回到观察者身上? (该组件以前使用过观察者,但是一些新的要求使事情变得更加复杂。)

2 个答案:

答案 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
  }
}