3

I am writing a test for a function that returns a promise, and am not able to run assertions on resolving or rejecting the promise. I cannot use ES6 on this project so I am using the rsvp.js library which claims to implement the Promises/A+ specification. I am using the latest qunit version 1.17.1

The function under test:

var loadGroups = function(data) {
     return new RSVP.Promise(function(resolve, reject) {
        var groups = [];
        // ... some code to populate the groups array
        if(groups.length > 0) {
            resolve(groups);
        } else {
            reject("No groups were loaded");
        }
    });
};

The success test:

test('success test', function(assert) {
    assert.expect(1);

    var promise = loadGroups(testData);

    promise.then(function(groups) {
        assert.deepEquals(groups.length, 1);
    });

    return promise;
});

This fails with "Expected 1 assertions, but 0 were run"


The failure test:

test('failure test', function(assert) {
    assert.expect(1);

    var promise = loadGroups([]);

    promise.then(null, function(message) {
        assert.equals(message, "No groups were loaded");
    });

    return promise;
});

This fails with "Promise rejected during get promise when loading empty groups: No groups were loaded"

carbontax
  • 2,164
  • 23
  • 37

1 Answers1

16

promises work by chaining. Promises are immutable wrappers over values.

When you do:

promise.then(function(e){
   // do something
});

You are not changing promise you are creating a new promise instead. Instead, you need to chain the promise:

test('success test', function(assert) {
    assert.expect(1);

    var promise = loadGroups(testData);

    // return the `then` and not the original promise.
    return promise.then(function(groups) {
        assert.deepEquals(groups.length, 1);
    });

});
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • I could understand this for the second case (where the test runned might expect a fulfilled promise), but in the first case the assertion should always be executed before the test runner is informed that the promise resolved? – Bergi Feb 24 '15 at 12:21
  • @Bergi remember what test runner we're talking about, what promises it's built for and what guarantees they lack :) – Benjamin Gruenbaum Feb 24 '15 at 13:01
  • I don't know Qunit, but assuming that it registers its own `then` handler to be notified of resolution, promises would guarantee to execute the assertion before that. – Bergi Feb 24 '15 at 13:03
  • 1
    @Bergi to be fair this whole `assert.expect(1)` thing is kind of silly :) – Benjamin Gruenbaum Feb 24 '15 at 13:26
  • 2
    @Benjamin QUnit.expect(1) is for this kind of case exactly. Where assertions are located inside of conditional blocks or callback functions the assertions may not get called, in which case it will appear that there is no error when in fact the assertion has not been tested. – carbontax Feb 24 '15 at 15:11
  • Doesn't this need a `var done = assert.async();` and a call to `done` in the final promise resolution? – Kato May 08 '15 at 19:02
  • @Kato the promise is returned here. Note the `return` – Benjamin Gruenbaum May 08 '15 at 19:03