Paul Cowan

Nomadic cattle rustler and inventor of the electric lasso

Emberjs - fillIn Test Helper With Key Events

I’ve imposed a self enforced ban on using observers when using ember. For example, I previously used two way binding in my template to bind the value attribute of an input element to a property

I would then create an observer on this bound value like this:

observer.js
1
2
3
queryDidChange: Ember.observer('query', function(){
  //some transofomation
}

This has generally led to a world of pain that I lamented about in this post.

What I do now in this situation is use something like the input DOM event:

input.js
1
2
3
4
5
  input: function(e) {
    var query = e.target.value || '';

    set(this, 'query', query);
    //do stuff

I can do any transformations in this event handler without the pain of obsevers or 2 way binding, I am in control of what is happening.

This is all well and good but what is not good is that this is not testable with the current ember test helpers.

There is the fillIn test helper but this will just set the value of an input to the supplied string without raising any key events:

fillIn.js
1
2
3
4
5
6
7
8
function fillIn(app, selector, contextOrText, text) {
  //init code

  run(function() {
    $el.val(text).change();
  });
  return app.testHelpers.wait();
}

What I needed was a way for the appropriate key events to be raised after every character. I might also have code in keydown and keyup for example.

With this in mind, I created this test helper to meet my requirements:

fillInWithInputEvents.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
function fillInWithInputEvents(app, selector, contextOrText, textOrEvents, events) {
  var $el, context, text;

  if (typeof events === 'undefined') {
    context = null;
    text = contextOrText;
    events = textOrEvents;
  } else {
    context = contextOrText;
    text = textOrEvents;
  }

  if (typeof events === 'string') {
    events = [events];
  }

  $el = app.testHelpers.findWithAssert(selector, context);

  $el.val('');

  focus($el);

  function fillInWithInputEvent(character) {
    var val = $el.val();
    var charCode = character.charCodeAt(0);

    val += character;

    run(function() {
      $el.val(val).change();
    });

    for (var i = 0, l = events.length; i < l; i++) {
      run($el, "trigger", events[i], { keyCode: charCode, which: charCode });
    }
  }

  for (var i = 0, l = text.length; i < l; i++) {
    fillInWithInputEvent(text[i]);
  }

  return app.testHelpers.wait();
}

The above helper will input the text one character at a time and raise any supplied events.

For example if I only want to raise an input event with each character then I would use it like this:

single.js
1
2
  visit('/')
    .fillInWithInputEvents('input.autosuggest', 'Michael', 'input')

Or if I want to raise more than one event then I can supply an array of input events:

multiple.js
1
2
  visit('/')
    .fillInWithInputEvents('input.autosuggest', 'Michael', ['input', 'keydown'])

You can use the helper like this in an ember-cli test-helper and I have created this pull request to get it included with the ember source.

Comments