2

I want to write a unit test that just displays the behavior of creating two promises, wrapping them up into one with $q.all and then test that the promises are both resolved at the same time.

  describe("Application controller", function() {
    var scope;
    var controller;

    beforeEach(module('my.namespace'));
//this suite can be removed.
    describe("Application ", function() {
        beforeEach(
            inject(function ($rootScope, $controller,$q) {
                scope = $rootScope.$new();
                controller = $controller('Application', {
                    '$scope': scope
                });
            }));


        it("should package two promises into one", function (done) {
            inject(function ($rootScope) {
                setTimeout(function () {
                    $rootScope.$apply(function () {
                        var promiseOne = $q.defer(),
                            //promiseOneData;
                            promiseTwo = $q.defer();
                            //promiseTwoData
                        promiseOne.then(function(data){
                            promiseOne.resolve('promiseOne');
                            expect(1).toBe(1);
                        });
                        promiseTwo.then(function(data){
                            promiseTwoData.resolve('promiseTwo');
                        })
                        var allPromises = $q.all([promiseOne,promiseTwo]);
                        allPromises.then(function(data){
                            //data should contain an array of two empty elements for each promise
                            expect(data.length).toBe(2);
                        });
                        done();
                    });
                }, 1000);


    })
});

With this I get the error: Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL. I don't want to actually use a get request for anything here, I just need two promises to be resolved and then moved into one promise that contains both. How can I do that with Angular and jasmine?

George Stocker
  • 57,289
  • 29
  • 176
  • 237
wootscootinboogie
  • 8,461
  • 33
  • 112
  • 197

2 Answers2

1

What you want is probably a spy and to see if it has been called or not.

describe('test $q', function() {
  var
    $scope;
    $controller;
    $httpBackend;

  beforeEach(function() {
    module('myModule');
    inject(function(_$rootScope_, _$controller_) {
        $scope = _$rootScope_.$new();
        $controller = _$controller_;
        $controller ('MyCtrl', {
          $scope: $scope
        });
    });

  it('should test that $q.all calls callback when dependent promises are resolved', function() {
    var deferOne = $q.defer(),
        deferTwo = $q.defer();
        combinedSpy = jasmine.createSpy('combined');    

    $q.all([deferOne.promise, deferTwo.promise]).then(combinedSpy);

    expect(combinedSpy).toNotHaveBeenCalled();
    deferOne.resolve();
    deferTwo.resolve();
    $scope.apply();
    expect(combinedSpy).toHaveBeenCalled();
  });

This test title is pretty confusing, you are not simulating a promise. You are testing a promise. And you don't have to, there are already tests for $q in Angular itself, so there is no point in you writing tests for that?

wrapping them up into one with $q.all

That creates a third promise. The third promise is resolved when both promise A and B have been resolved.

test that the promises are both resolved at the same time

JavaScript is single threaded, they cannot be resolved at the same time. The third promise, the one that is created by $q.all(), will be resolved when the first and second have both been resolved. Time may pass between A and B being resolved.

Say that A is resolved, an hour later B is resolved. Then C ($q.all) will be resolved in the next digest cycle (by $scope.apply()).

oldwizard
  • 5,012
  • 2
  • 31
  • 32
  • A lot of this answer is useful in that it tells people what not to do; but what should that test actually look like instead? that's the real useful answer, to show people what they should do. – George Stocker May 08 '15 at 21:17
  • Well, what he wants to do cannot be done, so what would the test look like? The premise that two things can be done at the same time in JS is incorrect. Also the question is unclear what he really wants, and the question has not improved. Testing if promises have been resolved is usually best done with spies, see this question. http://stackoverflow.com/questions/26319873/how-to-test-value-returned-in-promise-from-angularjs-controller-with-jasmine/26328984#26328984 – oldwizard May 09 '15 at 05:37
0

This is the OP's answer that they pasted into the question:

it("Should simulate promise",inject(function($q, $rootScope){
            var deferred = $q.defer();
            var promise = deferred.promise;
            var resolvedValue;
            promise.then(function(value){
                resolvedValue  = value;
            });
            //made no promises yet
            expect(resolvedValue).toBeUndefined();
            var application = {
                id: '123',
                name: 'suebalu',
                database: '234',
                folder: 'c:',
                version: '1.2',
                file: 'previewPubFile',
                date: '2009-01-01'
            };

            deferred.resolve({
                id: '123',
                name: 'suebalu',
                database: '234',
                folder: 'c:',
                version: '1.2',
                file: 'previewPubFile',
                date: '2009-01-01'
            });
            $rootScope.$apply();
            expect(resolvedValue).toEqual(application);
        }));
George Stocker
  • 57,289
  • 29
  • 176
  • 237