0

My problem is very similar to this post but just different enough that the accepted answer doesn't work for me. Essentially, I have an Angular factory which makes use of $compile, which returns a promise, and I want to mock it in Jasmine. Here is a simplified version of the factory:

angular.module('app.common')
.factory('myFactory', myFactory);

myFactory.$inject = ['$compile', '$rootScope'];
function myFactory($compile, $rootScope) {
    var factory = {
        testFunc: testFunc
    }
    return factory;

    function testFunc(stuff) {
        angular.element(document.body).append($compile(stuff)($rootScope));
    }
}

And here is my test:

describe("Common", function() {
    // I have many common services
    beforeEach(function() {
        angular.mock.module('app.common');
    });

    describe("Factory Example: ", function() {
        var mockCompile, mockRoot, aFactory;

        beforeEach(function() {
            module(function($provide) {
                $provide.value('$compile', jasmine.createSpy('$compile'));
                $provide.value('$rootScope', jasmine.createSpy('$rootScope'));
            });
        });

        beforeEach(inject(function($compile, $rootScope, myFactory, $q) {
            mockCompile = $compile;
            mockCompile = function() {
                var deferred = $q.defer();
                deferred.resolve('remote call result');
                return deferred.promise;
            };
            mockRoot = $rootScope;
            aFactory = myFactory;
        }));

        it('should work', function() {

            aFactory.testFunc('stuff');
            expect(true).toBe(true);
        });
    });
});

This code is complaining at me that $compile does not return a promise. It appears that $provide doesn't know about the new function assignment from inject. Ive been hacking around at it but Im new to Jasmine so I dont really know what Im doing. Any help would be appreciated - and if there's an easier way to do what Im trying to do please let me know!

Community
  • 1
  • 1
bradimus
  • 825
  • 11
  • 25

1 Answers1

2

Okay, hooray I solved it!

For those who may be interested in the future: The first problem was I was incorrectly assuming that $compile returns a promise, which it does not. It returns a function which takes the scope as an argument. If you do need to mock a function that returns a promise, check out this post which helped me figure out how.

Of course, that didn't work for me because all I needed to do was have my mocked $compile return a function. The following code worked for me:

describe("Common", function() {
// I have many common services
beforeEach(function() {
    angular.mock.module('app.common');
});

describe("Factory Example: ", function() {
    var mockCompile, mockRoot, aFactory;

    beforeEach(function() {
        module(function($provide) {
            // Just use callFake to have $compile return a function
            $provide.value('$compile', jasmine.createSpy().and.callFake(function() {
                return function(scope) { scope(); };
            });
            $provide.value('$rootScope', jasmine.createSpy());
        });
    });

    beforeEach(inject(function($compile, $rootScope, myFactory, $q) {
        mockCompile = $compile;
        mockRoot = $rootScope;
        aFactory = myFactory;
    }));

    it('should work', function() {

        aFactory.testFunc('stuff');
        expect(mockCompile).toHaveBeenCalled();
        expect(mockRoot).toHaveBeenCalled();
    });
});
Community
  • 1
  • 1
bradimus
  • 825
  • 11
  • 25