Search code examples
ember.jsqunitember-qunitember-testing

ember event trigger order is different in app and tests


I have written this simple demo component to demonstrate a problem. The component code is below

App.FocusOutComponent = Em.Component.extend({
  attributeBindings: ['tabindex'],

  tagName: 'focus-out',

  setFocus: function() {
    console.log('clicked focus-out container');
    this.$().find('button').focus();
    console.log('focus set to button');
  }.on('click'),

  focussedOut: function() {
    console.log('focussedOut from outer container');
  }.on('focusOut'),
});

{{#focus-out id="focus-container" tabindex="-1"}}
  <button id="text-button">Test Button</button>
{{/focus-out}}

When I run this and click on the focus-out element, this is the order of the logs. Link to demo

  1. clicked focus-out container
  2. focussedOut from outer container
  3. focus set to button

Now when I am trying to write acceptance tests for this with the following code.

test('test visit / and click button', function() {
  expect(0);
  visit('/').then(function() {
    find('focus-out').click();
    console.log('after click in test');
  });
});

The order of the logs are different. Link to demo.

  1. clicked focus-out container
  2. focus set to button
  3. after click in test
  4. focussedOut from outer container

The focusOut log got printed at the very end instead before the after click log. I was expecting the same order for the logs with just an additional log(after click) in the end.

Im not sure if this is a bug or something wrong with my code.

I also noticed another problem while executing tests. If I have focus on the chrome dev-tools while the tests are running, the focusOut event will not trigger at all.

Some help with this is much appreciated.


Solution

  • the click event doesn't set focus (being a back door route). You'll need to manually set focus then click if you want the same results.

    Ember's Click Helper (sends mousedown/mouseup, then click)

    function click(app, selector, context) {
      var $el = app.testHelpers.findWithAssert(selector, context);
      run($el, 'mousedown');
    
      if ($el.is(':input')) {
        var type = $el.prop('type');
        if (type !== 'checkbox' && type !== 'radio' && type !== 'hidden') {
          run($el, function(){
            // Firefox does not trigger the `focusin` event if the window
            // does not have focus. If the document doesn't have focus just
            // use trigger('focusin') instead.
            if (!document.hasFocus || document.hasFocus()) {
              this.focus();
            } else {
              this.trigger('focusin');
            }
          });
        }
      }
    
      run($el, 'mouseup');
      run($el, 'click');
    
      return app.testHelpers.wait();
    }
    

    Modified Test

    test('test visit / and click button', function() {
      expect(0);
      visit('/').then(function() {
        var el = find('focus-out');
        el.focus();
        click(el);
        console.log('after click in test');
      });
    });
    

    http://emberjs.jsbin.com/lefazevozi/1/edit?js,console,output

    It's also important to note, that tearing down will also call the focus out event. So the main reason you were seeing the focusout at all was because on teardown it was losing focus from the button child.

    Maybe focus should be set before mousedown on the click helper in the ember test, though I'm not sure what else that might affect, or if people wouldn't generally be expecting that since jquery doesn't do that.