简体   繁体   中英

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?

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM