1

I've been trying to wire up a simple backend to my Angular app and have decided to use Firebase, having had a good experience with them in a past app.

The app loads Firebase properly when I load it up in a browser, but I've run into a wall with failing unit tests via karma.

I've initialized a Directive and a Controller for a 'settings' screen that allows you to set a custom domain name for your app.

In its simplest form, it looks like this (see full source):

settingsController = function($scope, $element, $log, angularFire) {
    var domain = $scope.domain = "";
    var placeholder = $scope.placeholder = "e.g. www.strummer.io";
    console.log(angularFire);
    $scope.log = $log;
};

nav.directive('settings', function() {
    return {
        restrict: 'E',
        transclude: true,
        scope: { domain: '@' },
        controller: settingsController,
        templateUrl: 'static/nav/settings.html',
        replace: true
    };
});

When loaded in the browser, I see the angularFire object show up via the console.log command.

However, when I run my tests (via karma/jasmine), I am getting the error:

Error: Unknown provider: angularFireProvider <- angularFire
        at Error (<anonymous>)
        at /Users/dickason/code/strummer/builder/static/lib/angular.js:2696:15
        at Object.getService [as get] (/Users/dickason/code/strummer/builder/static/lib/angular.js:2824:39)
        at /Users/dickason/code/strummer/builder/static/lib/angular.js:2701:45
        at getService (/Users/dickason/code/strummer/builder/static/lib/angular.js:2824:39)
        at invoke (/Users/dickason/code/strummer/builder/static/lib/angular.js:2842:13)
        at Object.instantiate (/Users/dickason/code/strummer/builder/static/lib/angular.js:2874:23)
        at /Users/dickason/code/strummer/builder/static/lib/angular.js:4759:24
        at /Users/dickason/code/strummer/builder/static/lib/angular.js:4338:17
        at forEach (/Users/dickason/code/strummer/builder/static/lib/angular.js:138:20)
    Error: Declaration Location
        at window.jasmine.window.inject.angular.mock.inject (/Users/dickason/code/strummer/builder/static/lib/angular-mocks.js:1744:25)
    at null.<anonymous> (/Users/dickason/code/strummer/builder/static/nav/nav.spec.js:158:13)
    Error: Circular dependency:
        at Error (<anonymous>)
        at getService (/Users/dickason/code/strummer/builder/static/lib/angular.js:2817:17)
        at invoke (/Users/dickason/code/strummer/builder/static/lib/angular.js:2842:13)
        at Object.instantiate (/Users/dickason/code/strummer/builder/static/lib/angular.js:2874:23)
        at /Users/dickason/code/strummer/builder/static/lib/angular.js:4759:24
        at null.<anonymous> (/Users/dickason/code/strummer/builder/static/nav/nav.spec.js:170:20)
        at Object.invoke     (/Users/dickason/code/strummer/builder/static/lib/angular.js:2864:28)
        at workFn (/Users/dickason/code/strummer/builder/static/lib/angular-    mocks.js:1758:20)

Here is the test setup in question (see full source):

describe("directive: settings", function() {
        var scope;

        // Setup DOM
        var html, element, compiled;
        beforeEach(function() {
            html = '' +
            '<settings></settings>' +

            inject(function($compile, $rootScope) {
                scope = $rootScope;
                element = angular.element(html);
                compiled = $compile(element)(scope);
                scope.$digest();
            });
        });


        // Setup Controller
        var ctrl;
        beforeEach(inject(function($controller) {
            ctrl = $controller('settingsController', {$scope: scope, $element: null});
        }));

        it("Should retrieve the domain from the datastore", inject(function($controller, $rootScope) {
            // Test Controller

        }));

After some googling, I suspect this has something to do with the way angularFire is being injected into the controller.

I've tried the following solutions:

settingsController.$inject = ['$scope', '$element', '$log', 'angularFire'];

and

settingsController = ['$scope', '$element', '$log', 'angularFire', function($scope, $element, $log, angularFire) { ... }];

Both of which have left me with the same error.

Any suggestions would be appreciated.

2 Answers 2

3

Figured it out via some trial and error.

When the app is initialized, firebase is injected along with my main module ('nav').

When the tests are initialized, however, firebase doesn't get injected for some reason. By manually injecting it as a module before each test, you can avoid the 'unknownProvider' error.

Instead of:

beforeEach(module('nav'));

Use:

beforeEach(module('nav', 'firebase'));

Taking this approach allows you to inject 'angularFire' in the controller during each it('...') clause:

it("Should retrieve the domain from the datastore", inject(function($controller, $rootScope, angularFire) {
Sign up to request clarification or add additional context in comments.

Comments

1

Normally you would let angularFire be injected in nav.js to the app/module like so:

var nav = angular.module('nav', ['angularFire']);

and your settingsController

settingsController = function($scope, $element, $log, angularFire) { }

would be registered to the nav module like so with angularFire injected

nav.controller('settingsController', ['$scope', '$element', '$log', 'angularFire',
    function settingsController($scope, $element, $log, angularFire) {
        // Your code goes here
    }
]);

What if you register the settingsController with the 'nav' app instead of having it global, and inject angularFire into the 'nav' app?

1 Comment

I've tried this approach previously and see the error Error: No module: angularFire when injecting it into the 'nav' module. That seems to be the first problem. I can change the controller to be registered within the 'nav' app (copying/pasting exactly what you have) and I still get the same error: Error: Unknown provider: angularFireProvider <- angularFire

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.