Testing with callback function
Given the following factory that fetches a foobar
through a REST call:
1
2
3
4
5
6
7
8
9
10
|
angular.module('foobarApp').
factory('foobarFactory', function($resource) {
return {
getFoobar: function(callback) {
$resource('/rest/foobar').get(function(foobar) {
callback(foobar);
});
}
};
});
|
I need to test the following controller that depends on foobarFactory
:
1
2
3
4
5
6
7
8
|
angular.module('foobarApp').
controller('foobarCtrl', function($scope, foobarFactory) {
$scope.foobar = function() {
foobarFactory.getFoobar(function(foobar) {
$scope.foobarId = foobar.id;
});
};
});
|
To do so, I need to:
- Mock the
foobarFactory
and return a fake when calling the method getFoobar
1
2
3
|
spyOn(foobarFactory, 'getFoobar').andCallFake(function(fn) {
fn(foobar);
});
|
- Wait for
foobar
returned by the fake foobarFactory
1
2
3
|
waitsFor(function() {
return foobarFactory.getFoobar.callCount > 0;
}, 'Getting foobar timed out', 650);
|
1
2
3
4
|
runs(function() {
expect(scope.foobar.id).toBeDefined();
expect(scope.foobar.id).toEqual(123);
});
|
In the end, this is the final spec:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
describe('foobarCtrl', function() {
beforeEach(inject(function(foobarApp)));
// Mock
var foobarMock = {
id: 123
},
scope, foobarFactory, foobarCtrl;
beforeEach(inject(function($rootScope, $injector, $controller) {
foobarFactory = $injector.get('foobarFactory');
spyOn(foobarFactory, 'getFoobar').andCallFake(function(fn) {
fn(foobarMock);
});
scope = $rootScope.$new();
foobarCtrl = $controller('foobarCtrl', {
$scope: scope,
foobarFactory: foobarFactory
});
}));
it('should fetch the foobarId', function() {
waitsFor(function() {
return foobarFactory.getFoobar.callCount > 0;
}, 'Getting foobar timed out', 650);
runs(function() {
expect(scope.foobarId).toBeDefined();
expect(scope.foobarId).toEqual(123);
});
});
});
|
Testing promises
Given the following factory that also fetches a foobar
through a REST call, but returns a promise:
1
2
3
4
5
6
7
8
9
10
11
12
|
angular.module('foobarApp').
factory('foobarFactory', function($q, $resource) {
return {
getFoobar: function() {
var deferred = $q.defer();
$resource('/rest/foobar').get(function(foobar) {
deferred.resolve(foobar);
});
return deferred.promise;
}
};
});
|
I need to test the following controller that depends on foobarFactory
:
1
2
3
4
5
6
7
8
|
angular.module('foobarApp').
controller('foobarCtrl', function($scope, foobarFactory) {
$scope.foobar = function() {
foobarFactory.getFoobar().then(function(foobar) {
$scope.foobarId = foobar.id;
});
};
});
|
To do so, I need to:
1
2
3
|
var foobarMock = {
id: 123
};
|
- Create a promise that return the previous
foobar
mock
1
2
|
var deferred = $q.defer();
deferred.resolve(foobarMock);
|
- Mock the
foobarFactory
and return the previous promise
1
|
spyOn(foobarFactory, 'getFoobar').andReturn(deferred.promise);
|
1
2
3
4
5
6
7
8
9
|
var result;
foobarFactory.getFoobar().then(function(foobar) {
result = foobar;
});
expect(result).toBeUndefined();
$rootScope.$apply();
expect(foobarFactory.getFoobar).toHaveBeenCalled();
expect(result).toBeDefined();
expect(result).toBe(foobarMock);
|
In the end, this is the final spec:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
describe('foobarCtrl', function() {
beforeEach(inject(function(foobarApp)));
// Mock
var foobarMock = {
id: 123
},
$rootScope, scope, foobarFactory, foobarCtrl;
beforeEach(inject(function(_$rootScope_, $injector, $controller, $q) {
$rootScope = $rootScope;
scope = $rootScope.$new();
foobarFactory = $injector.get('foobarFactory');
var deferred = $q.defer();
deferred.resolve(foobarMock);
spyOn(foobarFactory, 'getFoobar').andReturn(deferred.promise);
foobarCtrl = $controller('foobarCtrl', {
$scope: scope,
foobarFactory: foobarFactory
});
}));
it('should fetch the foobarId', function() {
var result;
foobarFactory.getFoobar().then(function(foobar) {
result = foobar;
});
expect(result).toBeUndefined();
$rootScope.$apply();
expect(foobarFactory.getFoobar).toHaveBeenCalled();
expect(result).toBeDefined();
expect(result).toBe(foobarMock);
});
});
|