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

Simulating user input in Ember component tests

我正在尝试为模拟真实用户输入的 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,在 "Interacting with Rendered Components" 下)。

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

我找到了几种解决此问题的方法,具体取决于您的舒适程度。不幸的是,它们都不涉及简单地对测试本身进行更改,所以我仍然很高兴听到是否有人有更好的解决方案。

一:解决问题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

我认为这是因为 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
  }
}