4

I have AngularJS app with unit tests covering it. I added one more http request in .run part of application which checking user authentication. Now about 60% of my tests fails because they found 'unexpected http request'. Even directives tests are fail. How can I avoid running this request in tests? How can I easily mock this request in all tests? Im trying to not to put httpBackend.expect('GET', 'URL') to each test - that's too much work.

Testing with Jasmine + Karma

Thanks. I can give more details if needed.

Fyodor Khruschov
  • 1,657
  • 7
  • 23
  • 40

2 Answers2

2

There are a few ways to do this:

1.) Include a beforeEach that Tim Castelijns suggested but for every spec file
2.) Include the beforeEach in a separate file called app-mocks.js & include in your karma.conf.js (I'm guessing you have one).

karma.conf.js

files: [
    'location/of/app-mocks.js',
    'src/app/**/*.js'
],

app-mocks.js

(function () {
    'use strict';

    beforeEach(inject(function ($httpBackend) {
        $httpBackend.whenGET('blahblahblah.com/cat/:id/food').respond('');
    }));
})();

3.) Separate out user authentication logic from the core app and create an $http wrapper service (suggested). Thus you could have (simplified example):

app.js

angular.module('myApp', ['myApp.services']);

user-service.js

angular.module('myApp.services', [])
    .factory('User', function ($http) {
        function authenticate() {
            // authenticate user
        }

        return {
            authenticate: authenticate
        };
    });

and same for your directives, controllers, etc. This way, you can unit test all of your components in isolation without having to worry about intertwined logic that is actually specific to one type of functionality. Also, when you do test core app functionality, you can just mock or spy on your User service. In your spec files you would inject only the module & functionality you are testing. So instead of injecting your entire core app module, you would:

To test services

beforeEach(module('myApp.services'));

To test directives

beforeEach(module('myApp.directives'));

etc.

Of Note: When your application starts to get big, I would consider organizing your app components based on feature rather than by type as this example above does.

daviskoh
  • 76
  • 7
0

You can use a beforeEach block to define a call that all tests should expect

var httpBackend;
beforeEach(inject(function(_$httpBackend_) {
  httpBackend = _$httpBackend_;
  httpBackend.expect('GET', 'URL').respond('');
}

Note the .respond('') I added, an expect call needs this, see the documentation if you want to know why.

This beforeEach functionality comes with the widely used jasmine testing framework.

Tim
  • 41,901
  • 18
  • 127
  • 145
  • thanks. This is good solution, but I have about 10 (it's just a start of a project) test files. And I know how to mock this request, I ask to find better way to do it. Why I need to mock request from `.run` block if I test, for example, directive? This is my vision. It might be wrong. – Fyodor Khruschov Jun 11 '14 at 09:24
  • @n8m well, this at least makes it so that you don't have to add the request to each individual test, just once per test file – Tim Jun 11 '14 at 09:25
  • @n8m I don't think you want to set add this request for ALL tests, because the tests that don't need to mock this request will fail if they don't trigger the expected call – Tim Jun 11 '14 at 09:28
  • I didn't going to add mock request individually to each test. Of course I would use `beforeEach` block. But I'm trying to find another way. Thanks anyway for your answer – Fyodor Khruschov Jun 11 '14 at 09:29