Search code examples
javascriptangularjsrequirejskarma-runnerangular-amd

'undefined' is not an object (evaluating 'app.register.service') when using requirejs, angularamd and karma


In our angularjs project, we are using requirejs + angularAMD to manage dependencies. The application works fine, but we're having problems when running the jasmine tests using karma.

This is the error:

    TypeError: 'undefined' is not an object (evaluating 'app.register.service')
  at /home/bcatarino/Projects/spr/target-grunt/js/app/model/PressRelease.js:3

It seems that our app is not correctly injected into our test.

The source code for the test:

'use strict';

define(['angularAMD', 'pressRelease'], function(angularAMD, pressRelease) {

    describe('PressReleaseModel test', function () {

        var scope, pressReleaseModel;

        var inject = angularAMD.inject;

        inject(function (pressRelease) {
            pressReleaseModel = pressRelease;
        });


        it('Should add a non-existing recipient', function(pressRelease) {
            expect(pressReleaseModel.get().recipients.length, 0);
        });
    });
});

PressRelease is coded like this:

define([ 'app', 'angularAMD' ], function(app, angularAMD) {

    app.register.service('pressRelease', function() {

    //Stuff going on here

    } );

});

So this is where app.register is undefined and we can't figure out why.

As requested, here's the karma.conf:

module.exports = function(config) {
    config.set({
        basePath: '../../../',
        files: [
            {pattern: 'js_components/angular/angular.js', watched: false, included: false},
            {pattern: 'js_components/angular-mocks/angular-mocks.js', included: false},
            {pattern: 'js_components/angularAMD/angularAMD.js', included: false},
            {pattern: 'js_components/angular-ui-router/release/angular-ui-router.min.js', included: false},
            {pattern: 'js_components/angular-ui-utils/ui-utils.js', included: false},
            {pattern: 'js/test/test-app.js', watched: true, included: false},
            {pattern: 'js/app/model/PressRelease.js', watched: true, included: false},
            {pattern: 'js/test/model/PressReleaseModelSpec.js', watched: true, included: false},
            'js_components/requirejs/require.js',
            'js/test/test-main.js'
        ],
        exclude: [],
        plugins: [
            'karma-jasmine',
            'karma-phantomjs-launcher',
            'karma-chrome-launcher',
            'karma-requirejs'
        ],
        frameworks: ['jasmine', 'requirejs'],
        junitReporter: {
            outputFile: 'karma-test-results.xml',
            suite: ''
        },
        port: 9876,
        runnerPort: 9100,
        browsers: ['PhantomJS', 'Chrome'],
        autoWatch: true,
        preprocessors: {
            'template/**/*.html': ['html2js']
        },
        ngHtml2JsPreprocessor: {
            // strip this from the file path
            stripPrefix: 'web',
            moduleName: 'templates'
        },
        logLevel : config.LOG_INFO
    })
};

Anyone has any ideas? We're following this as example, but we're not finding the answer: https://github.com/marcoslin/angularAMD

Thanks


Solution

  • I solved it by removing AngularAMD from unit tests. I created a bridge that redirects app.register.method to app.method where app is an Angular module.

    define([
        'angularMocks',
        'angular'
    ], function () {
        'use strict';
        var myapp = angular.module('SPR', []);
    
        myapp.register = {};
        var enhanceModule = function (method) {
            var register = myapp.register;
            register[method] = angular.bind(myapp, myapp[method]);
        };
    
        angular.forEach([
            'controller',
            'directive',
            'filter',
            'factory',
            'service',
            'constant',
            'value',
            'animation']
        , enhanceModule);
    
        console.info('Enhanced angular.module');
        return angular.module('SPR');
    });
    

    This is the test:

    define(['angularMocks', 'app', 'js/app/model/PressRelease'], function (mocks) {
    
        describe('Press Release model', function () {
    
            var service;
            beforeEach(mocks.module('SPR'));
            beforeEach(mocks.inject(function (PressRelease) {
                service = PressRelease;
            }));
    
            it('should do something', function () {
                var res = service.serviceCall();
                expect(res).toBe(1);
            });
    
        });
    });