Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing injected service that is a constructor function

Say I have a service like this, where a car gets an engine service injected, which is a constructor function:

angular.module('car', ['engine']).factory('carCreator', function( engine ) {

    var carCreator = function( settings ) {

        var engineInstance = engine( settings );
        engineInstance.setMiles( settings.engine.miles );

        return {
            brand: settings.brand;
            engine: engineInstance;
        }
    };

    return carCreator;
});

How do I test both lines in the initialization logic:

var engineInstance = engine( settings );
engineInstance.setMiles( settings.engine.miles )

1: That engine is called with settings

2: That engineInstance.setMiles is called with settings.engine.miles

This is what I'm doing right now, but with no luck:

describe('initialization', function() {

    var carCreator;
    var settings = {
        brand: 'Ford',
        engine: {
            miles: 12000
        }
    };

    var mockEngineInstance = {
        setMiles: function() {}
    };

    window.mockEngineCreator = function() {
        return mockEngineInstance;
    }

    beforeEach(module('car', function($provide) {
        $provide.value('engine', mockEngineCreator );
    }));

    beforeEach(inject(function(_carCreator_) {
        carCreator = _carCreator_;
    }));

    it('should init text object correctly on initialization', function() {

        spyOn(window, 'monkEngineCreator');
        spyOn(mockEngineInstance, 'setMiles');
        carCreator( settings );

        expect(window.mockEngineCreator).toHaveBeenCalledWith( settings );
        expect(mockEngineInstance.setMiles).toHaveBeenCalledWith( settings.engine.miles );
    });
});

but this test fails, saying that window.mockEngineCreator never was called. It seems that $provide creates a new copy of the function passed in, instead of keeping a reference to it. So, does anyone know how to setup a test that can test this correctly?

like image 926
acrmuui Avatar asked Dec 04 '13 21:12

acrmuui


1 Answers

The reason for this is that when you run spyOn(window, 'monkEngineCreator'), the spy is put on window, not the injected value that angular uses for dependency injection.

Doing something like this should work: (untested code)

beforeEach(module('car', function($provide){
    $provide.value('engine', jasmine.createSpy('engineSpy').andCallFake(function(){
        return mockEngineInstance;
    }));
}));

it('should init', inject(function(carCreator, engine){
    var settings = {};
    carCreator(settings);

    expect(engine).toHaveBeenCalledWith(settings);
}));
like image 107
Clark Pan Avatar answered Oct 21 '22 03:10

Clark Pan