Using Jamine to test an AngularJS service without mocks - angularjs

I would like to use Jasmine to write tests (not unit tests) for an AngularJS service I have, which is a wrapper for a REST API I created on my server. The service call should actually get all the way to the server. No mocking needed.
I want to be able to test some scenarios involving combinations of few of these API calls.
I understand I should probably not be using angular-mocks.js but I can't figure out the syntax for getting access to the service instance in the test.
I have something like the code below. As you can see where the ?? I would like to assign the service reference to myService so I could use it in the tests.
beforeEach(function () {
module("myApp");
myService = ??
});
Also, should I include only the service file in the specRunner.html references list?

You will just need to have something like the following:
$httpBackend.whenGET(/\/your-url-here-\/.*/).passThrough();

Related

Selectively Mock Services when Testing Angular with Karma

While there have been many questions around mocking an individual Angular service in Karma, I am having an issue with making my mocks more ubiquitous throughout testing my application.
In my current setup, I have a module called serviceMocks that includes a factory with a mock of each service in the application.
Contrived example:
angular.module('serviceMocks',['ngMock'])
.factory('myServiceOne', function() {...})
.factory('myServiceTwo', function($httpBackend,$q) {...})
This works great when testing controllers and directives which may use one or more services as a dependency. I include my app's module and the serviceMocks module within my testfile, and each service is properly substituted.
beforeEach(module('myApp'));
beforeEach(module('serviceMocks'));
it('properly substitutes mocks throughout my tests', function() {...});
However, when testing a service itself I cannot include the serviceMocks module, as the service I am testing is substituted by its mock making the tests useless. However, I would still like all other services mocked as a service may depend on one or more services for its execution.
One way I thought of doing this was to make my service mocks globally available, perhaps by attaching an object to window that holds the mocks. I could then include the mocks individually when testing services like so:
beforeEach(module('myApp', function($provide) {
$provide.value('myServiceOne',window.mocks.myServiceOneMock);
$provide.value('myServiceTwo',window.mocks.myServiceTwoMock);
});
However this approach did not work, because some of the mocks use $q or other angular services to function properly, and these services are not properly injected when simply attaching the factory object to the window.
I am looking for a way to test services while having a single location to define mocks for all services. Possibilities I imagine but have been unable to succeed with:
A) Have the serviceMocks module's .run() block run before the
config stage for myApp's module. (In which case I could attach
each service to the window as the angular dependencies would be
properly injected, and inject each as shown above)
B) Be able to override the service that I'm testing with its actual implementation in the test files of each service
C) Otherwise be able to define and access these mocks globally, while still ensuring each mock has access to certain angular services such as $q.
The question contains a clue to the answer. If serviceMocks module causes design issues, using it is a mistake.
The proper pattern is to have one module per unit (mocked service in this case). ngMock is not needed, it is loaded automatically in Jasmine tests. The modules can be used one by one:
beforeEach(module('app', 'serviceOneMock', 'serviceTwoMock'));
Or joined together:
angular.module('serviceMocks', ['serviceOneMock', 'serviceTwoMock'])
There are not so many cases when serviceMocks module should exist at all. Just because a decision which services should be mocked and which should not is made for each describe block.
Most times mocked services are individual for current spec or depend on local variables. In this case the services are mocked in-place:
var promiseResult;
beforeEach(module('app'));
beforeEach(module({ foo: 'instead of $provide.value(...)' });
beforeEach(($provide) => {
$provide.factory('bar', ($q) => {
return $q.resolve(promiseResult);
}
});
...
Doing this in dedicated serviceOneMock, etc. modules may require mocked services to be refactored any moment it becomes obvious they are too generic and don't suit the case well.
If mocked service is used more than once in specs with slightly different behaviour and results in WET tests, it is better to make a helper function that will generate it for current spec rather than hard-coding it to serviceOneMock, etc. modules.

AngularJS unit testing: Constructor Test: Windows Azure Invoke Api

I am making an Hybrid App using Ionic(AngularJS).
I have a generic factory which uses an invoke Api method of WindowsAzureService JS SDK. And I am unit testing my application.
var mClient = new WindowsAzure.MobileServiceClient(applicationUrl,applicationKey);
mClient.invokeApi(api, data, header)).done(function (res) {
// do something
})
I am not using $http, so I can't mock test cases with a $httpBackend. I would like some help on how to test api calls using windowsAzureServices.
Also how to I spyOn this constructor?
Github link to SDK
There isn't a test harness for Mobile Services. You'll want to follow JB Nizet's advice and create one which can mockup the results you expect.
Alternatively, you can call the API directly and set the appropriate ZUMO headers for auth. Then you can use $http and $httpBackend. It's worth checking out Mobile Services GitHub and looking at how they run E2E tests against the client. You can probably use something similar.

Angular ngmock httpBackend - ignore all but one request?

I am new to writing unit tests, so apologies if this is a dumb question. If I'm trying to test a method in an Angular controller that relies on mock data from a service call, and I want to also mock that service call (ngResource), is there a way to make httpBackend ignore other requests made in my controller on initialization?
I've tried placing my whenGET or expectGET definitions in before blocks, and only instantiating my controller within my test, but I always find that httpBackend is expecting other requests (Error: Unexpected request) when I call flush(). I do not want to write mocks for all other requests, just the one I'm using for this test.
Of course, this may be a stupid idea, as I can also just provide the fake data directly, and not test the service along with the controller's method. I've verified that this works. Maybe the correct answer is that I shouldn't be testing services from within a controller.
FWIW, I've also tried using Sinon fakeServer, and apparently it doesn't even pick up on Angular's XHR implementation (the server never responds).

Possible to write test for controller without $httpbackend?

Im trying to understand Angularjs. I have a controller that contains one function and one http.get. Is it possible to write a Karma unittest for the function without mocking $httpbackend? Right now i get the error unexpected http call and the test newer runs.
If you are using angular-mocks.js, which I assume you are as you're using Karma, $httpBackend is already mocked. You just need to define your expectations, which can be very loose. Like so:
$httpBackend.when('GET', '/expected-url').respond(200, '');
If you want to use the real $httpBackend, don't include ngMock, but I won't recommend that :)

Mocking an asynchronous web service in Angular unit tests

I'm building an Angular app, and I'm writing unit tests for it. Yay unit tests. I want to mock a particular web service that I'm using (Filepicker.io), which has both a REST API as well as a Javascript API. In my code I use the Javascript API in calls like
filepicker.store(file,
{
options: 'go',
right: 'here'
},
// filepicker's success callback
function(resultObject){
// do stuff with the returned object
}
I know that I could use the $httpBackend provider if I were interacting with Filepicker's REST API, but since my application's code isn't doing that, I'm wondering if/how I could mock an asynchronous API call like this in an Angular unit test.
Do I just override the store method (or the whole filepicker object) in context of my test suite and make it return dummy data of my choosing? That's what they're doing with AngularFire development, with a library that overrides the 'real' Firebase backend service.
Alternately, could I wrap the method in something that uses $httpBackend, so I can use all those handy $httpBackend methods like respond? What's the right strategy here? The first one seems like a simpler and cleaner idea.
Here are some other questions that were similar but ultimately not clear enough for me to fully understand.
AngularJS: unit testing application based on Google Maps API
Unit testing Web Service responses
Mocking Web Services for client layer unit testing
I would first set your SDK as an injectable Service so it can be used more easily by your angular app
myApp.factory('FilePicker',function(){
//likely coming from global namespace
return filepicker;
})
.controller('ctrl',['FilePicker',function(FilePicker){
//use File picker
}];
Now you should be able to inject a mock instead of the real implementation for your tests.
An example with a our controller
describe('ctrl test', function(){
var ctrl;
beforeEach(inject(function($controller){
var mockService={} // here set up a mock
ctrl=$controller('ctrl',{FilePicker:mockService});
}));
});

Resources