Karma testing with .success() getting 'undefined' is not an object'
angularjs, karma-runner, unit-testing
Solution
Replace this:
var mockStudentsProvider = {
getStudents: function getStudents() {
return [{
Education: [],
Person: [{
ID: 1,
Name: "Testing McTestsson",
SSN: "1234567890",
Address: "Fakestreet 3",
MobilePhone: "7777777"
}]
}];
}
};
with this:
var mockStudentsProvider = {
getStudents: function getStudents() {
var retVal = [{
Education: [],
Person: [{
ID: 1,
Name: "Testing McTestsson",
SSN: "1234567890",
Address: "Fakestreet 3",
MobilePhone: "7777777"
}]
}];
return {
success: function(fn) {
fn(retVal)
};
}
}
};
And replace this:
spyOn(StudentsProvider, 'getStudents');
with this:
spyOn(StudentsProvider, 'getStudents').andCallThrough();
When you do not use `andCallThrough()` or `andCallFake()` jasmine prevents execution of the method and returns null. Inside your update method you are calling `null.success`. This will fail. (http://jasmine.github.io/1.3/introduction.html)
In your mock method you need to change the return format--the real http method returns an object where success refers to a function which takes an input a callback function.
In your case, the callback function is:
function(data) {
$scope.students = data;
}
Problem
I'm trying to write a unit test to see if the 'getStudents()' provider function in my controller gets called if some properties are appropriately set. Notice the .success() callback: ``` $scope.update = function update() { // omitted, just doing some checking... // finally else if (key.length === 3 || $scope.students.length === 0) { StudentsProvider.getStudents($scope.keyword, $scope.selectedFilters).success(function(data) { $scope.students = data; }); } }; ``` My karma unit test looks like this: ``` describe("Students: Controllers", function () { var $scope; var ctrl; beforeEach(module('studentsApp')); describe("SearchCtrl", function () { // Mock the provider var mockStudentsProvider = { getStudents: function getStudents() { return [ { Education: [], Person: [{ ID: 1, Name: "Testing McTestsson", SSN: "1234567890", Address: "Fakestreet 3", MobilePhone: "7777777" }] } ]; } }; var StudentsProvider; beforeEach(inject(function ($controller, $rootScope) { $scope = $rootScope.$new(); ctrl = $controller('SearchCtrl', { $scope: $scope, StudentsProvider: mockStudentsProvider}); StudentsProvider = mockStudentsProvider; })); describe("Update", function () { beforeEach(function () { spyOn(StudentsProvider, 'getStudents'); }); it("should always call the provider with 3 letters", function () { $scope.keyword = "axe"; $scope.update(); expect(StudentsProvider.getStudents).toHaveBeenCalled(); expect(StudentsProvider.getStudents).toHaveBeenCalledWith("axe", ""); }); }); }); }); ``` When I run this, I get the following error: ``` TypeError: 'undefined' is not an object (evaluating 'StudentsProvider.getStudents($scope.keyword, $scope.selectedFilters).success') ``` and it's probably because I'm not mocking the .success() callback. How would I do that? Thanks in advance!