Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing actions in ember controller that return promises

I have a controller that performs an asynchronous operation, which I would like to test:

/*globals Ember, momnent*/
import { raw as icAjaxRaw } from 'ic-ajax';

//...

    actions: {
        foo: function() {
            var req = icAjaxRaw({
                type: 'POST',
                url: ApiUtils.apiUrl+'/dofoo',
                processData: false,
            });

            return req.then(
                function resolve(result) {
                    console.log(result.response);
                    this.set('fooLastDoneAt', moment());
                }.bind(this)
            );
        },

... and in the tests:

test('actions.foo', function() {
    expect(2);
    var ctrl = this.subject();
    var model = {
        fooLastDoneAt: moment().add(-10, 'days'),
    };
    ctrl.set('model', model);
    ok(ctrl.get('fooLastDoneAt').isBefore(moment().add(-1, 'days')), true, 'initial');
    ctrl.send('foo');
    ok(ctrl.get('fooLastDoneAt').isBefore(moment().add(-1, 'days')), false, 'updated date');
});

However, this inevitably results in an error being thrown, in another, unrelated, test case:

"Uncaught Error: Assertion Failed: calling set on destroyed object"[

which must be occurring because this.set('fooLastDoneAt', moment()); is executed after this test case has finished, and the test runner has done a teardown for this module, and gone on to the next one; while the action is still executing.

Is there a way for me to wait for an action to complete, asynchronously, before moving on to the next step the unit test?


@kingpin2k suggests this solution, where you pass in a promise deferred object into the action. However, in my app, the app itself would never do this, and it seems like a fundamental problem if I need to modify my app source just so that it can be tested - especially since it adds added complexity.

Are there any other ways to make the test execution wait for the action to complete?

like image 748
bguiz Avatar asked Mar 15 '26 09:03

bguiz


1 Answers

I would go for QUnit start() stop() functions.

Here is example of using taken from QUnit documentation:

QUnit.test( "a test", function( assert ) {
  QUnit.stop();
  asyncOp();
  setTimeout(function() {
    assert.equals( asyncOp.result, "someExpectedValue" );
    QUnit.start();
  }, 150 );
});

Also ember-qunit library covers this with then.

Here is example for ember-qunit

test('actions.foo', function() {
    expect(2);
    var ctrl = this.subject();
    var model = {
        fooLastDoneAt: moment().add(-10, 'days'),
    };
    ctrl.set('model', model);
    ok(ctrl.get('fooLastDoneAt').isBefore(moment().add(-1, 'days')), true, 'initial');
    ctrl.send('foo').then(function(){
      ok(ctrl.get('fooLastDoneAt').isBefore(moment().add(-1, 'days')), false, 'updated date');
    });
});

I didn't test the code so I hope it solves your problem

like image 159
saygun Avatar answered Mar 17 '26 23:03

saygun



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!