devdropper87 devdropper87 - 3 months ago 54
AngularJS Question

unable to inject module/service for unit test

I am new to TDD and am trying to wire up a test, and have been stuck on it for hours. I keep getting the following error:

[$injector:modulerr] Failed to instantiate module AuthInterceptor due to:
Error: [$injector:nomod] Module 'AuthInterceptor' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
http://errors.angularjs.org/1.5.8/$injector/nomod?p0=AuthInterceptor
at client/test/index.js:8237:13
at client/test/index.js:10251:18
at ensure (client/test/index.js:10175:39)
at module (client/test/index.js:10249:15)
at client/test/index.js:12786:23
at forEach (client/test/index.js:8490:21)
at loadModules (client/test/index.js:12770:6)


Here is my test:

import angular from 'angular';
import serviceModule from './auth.interceptor'

describe('wire.common.services', () => {

describe('AuthService', () => {
let AuthService;

beforeEach(angular.mock.module(serviceModule.name));
beforeEach(angular.mock.module(($provide) => {
$provide.factory('$q', () => ({}));
$provide.factory('$log', () => ({}));
}));

beforeEach(angular.mock.inject((_AuthService_) => {
AuthService = _AuthService_;
}));

it('should be a dummy test', () => {
expect(2).toEqual(2);
});

});

});


The actual code I'm testing:

export default function AuthInterceptor($q, $injector, $log) {
'ngInject';
return {
request(config) {
let AuthService = $injector.get('AuthService');
if (!config.bypassAuthorizationHeader) {
if (AuthService.jwtToken) {
config.headers.Authorization = `Bearer ${AuthService.jwtToken}`;
} else {
$log.warn('Missing JWT', config);
}
}
return config || $q.when(config);
},
responseError(rejection) {
let AuthService = $injector.get('AuthService');
if (rejection.status === 401) {
AuthService.backToDAS();
}
return $q.reject(rejection);
}
};

}


I don't understand why I'm getting this error - I provided all the dependencies for the service and am following what is outlined in the angular documentation. any help is appreciated!

Update, this is the code that I went with:

import angular from 'angular';
import AuthInterceptor from './auth.interceptor'

describe('Auth interceptor test', () => {

describe('AuthInterceptor test', () => {
let $httpBackend, $http, authInterceptor = AuthInterceptor();

beforeEach(angular.mock.module(($httpProvider, $provide) => {
$httpProvider.interceptors.push(AuthInterceptor);
$provide.factory('AuthService', () => ({
jwtToken: "hello",
backtoDAS: angular.noop
}));
}));

beforeEach(inject(function($injector) {
$httpBackend = $injector.get('$httpBackend');
$http = $injector.get('$http');
}))


it('should have a request function', () => {
let config = {};
expect(authInterceptor.request).to.be.defined;
expect(authInterceptor.request).to.be.a('function');

})

it('the request function should set authorization headers', (done) => {
$httpBackend.when('GET', 'http://jsonplaceholder.typicode.com/todos')
.respond([{
id: 1,
title: 'Fake title',
userId: 1
}]);
$http.get('http://jsonplaceholder.typicode.com/todos').then(function(transformedResult) {

expect(transformedResult.config.headers.Authorization).to.be.defined;
expect(transformedResult.config.headers.Authorization).to.contain('Bearer')
done();
})
$httpBackend.flush();
});

it('should have a responseError function', () => {
expect(authInterceptor.responseError).to.be.defined;
expect(authInterceptor.responseError).to.be.a('function');
//TODO: test return value
// see that AuthService.backToDAS()
})

it('the error function should call backtoDAS', (done) => {
//the URL should be one that gives me a 401
$httpBackend.when('GET', 'https://wwws.mint.com/overview.event')
.respond([{
id: 1,
title: 'Fake title',
userId: 1
}]);
$http.get('https://wwws.mint.com/overview.event').then(function(transformedResult) {

console.log(transformedResult);
done();
}, function(error){
console.log(error);
done();
})

});

})
});

Answer

This means that AuthInterceptor Angular module wasn't defined (and by the way, relying on name is unsafe).

AuthInterceptor isn't a module but an injectable function. It can be tested in functional fashion as $http interceptor:

beforeEach(angular.mock.module(($httpProvider) => {
  $httpProvider.interceptors.push(AuthInterceptor);
});

...

it('...', () => {
  $httpBackend.when(...).respond(...);
  $http.get(...).then((interceptedResult) => {
    expect(interceptedResult)...
  });

  $rootScope.$digest();
});

or directly:

it('...', () => {
  let interceptor = $injector.invoke(AuthInterceptor);
  expect(interceptor).toEqual({
    request: jasmine.any(Function),
    requestError: jasmine.any(Function)
  });

  var config = { headers: {} };
  interceptor.request(config);
  expect(config)...
});

Services that produce side effects (AuthService, $log) should be stubbed.