I'm having difficulties understanding how to resolve the problem of the unit testing the controller, which makes a GET call during initialisation.
When testing the controller method, that performs the POST request, because of the initial GET call I'm getting the following error in my tests:
Error: Unexpected request: GET
The main part of the controller looks like this:
.controller('someController', function($scope, $http, $log) {
$scope.posts = [];
$scope.content = '';
$scope.read = function() {
$http.get('/read.php')
.success(function(data) {
$scope.posts = data;
})
.error(function(data, status, headers, config) {
throw new Error('Something went wrong with reading data');
});
};
$scope.read();
$scope.write = function() {
$http({
method: 'POST',
url: '/write.php',
data: "content=" + $scope.content,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})
.success(function(data) {
$scope.posts.push({ id : data.id, task : $scope.content })
})
.error(function(data, status, headers, config) {
throw new Error('Something went wrong with writing data');
});
};
});
As you can see I'm calling the read() method right after its definition - so that all records are fetched from the database on page load.
I've tried the same with the .config() or other service, but obviously the result is the same.
Now - my test is as follow:
describe('someController tests', function() {
var $scope,
$http,
$httpBackend,
$log;
beforeEach(function() {
module('myApp');
inject(function($rootScope, _$http_, _$httpBackend_, _$log_) {
$scope = $rootScope.$new();
$http = _$http_;
$httpBackend = _$httpBackend_;
$log = _$log_;
});
$httpBackend.expectGET("/mod/read.php").respond({});
});
it('should add new record', inject(function($controller) {
$controller('ToDoController', {
$scope : $scope,
$http : $http,
$log : $log
});
$scope.posts = [];
$scope.content = 'Some content';
$httpBackend
.whenPOST('/write.php')
.respond({ id : 1, content : $scope.content });
$scope.write();
$httpBackend.flush();
expect($scope.posts.length).toBe(1);
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
}));
});
Now - there are a few questions I have about this code.
Is calling the method within the controller on page load considered a good practice? I know that if I used ng-init within the document to call it - this would solve all my problems, but I just don't like this approach.
In the beforeEach() method of the test I'm calling:
$httpBackend.expectGET("/mod/read.php").respond({});
to reflect the call of the read() method during initialisation, but again - I'm not sure this is the right thing to do here. I know that if I remove it - the 'should add new record' test will fail with the error mentioned above.
I know that afterEach() should be placed outside of the it() block, but if I do this - it will cause the same problem, but error will apply to all of the tests within this describe block. Is putting it inside of the it() block considered a bad practice / incorrect?
How would I perform the read() test - if the call is already triggered in the beforeEach() loop?
Lastly - what would your suggestion be to improve / rewrite the controller and the test to make sure it works its best?
I'm pretty new to the TDD - so I'm sure it's just my limited understanding of the topic, but would appreciate some constructive help.