How I unit test $ scope.broadcast, $ scope. $ When using Jasmine
I'm new to the AngularJs / NodeJs world, so goodbye if this is a basic question for some.
So, in a nutshell, I have two controllers, the first controller is $broadcast
"Id" and the second controller retrieves this id using $on
and then passes that id to an intermediate service
, which $http
ajax does and returns one object Book
.
How I unit test $ scope.broadcast, $ scope. $ when using Jasmine
firstCtrl
.controller('firstCtrl', function($scope, ...){
$scope.selectGridRow = function() {
if($scope.selectedRows[0].total !=0)
$scope.$broadcast('id', $scope.selectedRows[0].id);//Just single plain ID
};
});
secondCtrl
.controller('secondCtrl',
function($scope, bookService) {
$scope.$on('id', function(event, id) {
bookService.getBookDetail(id).then(function(d) {
$scope.book = d.book;
});
});
});
expected Json obj
var arr = "book" : [ {
"id" : "1",
"name" : "Tomcat",
"edition" : "9.1"
}
]
Let me know if anyone wants me to publish the service $http
used by the second controller.
expected behavior
So, from the very beginning of my head, ideally, I would like to test all possible scenarios, but something like below that can then waste:
expect(scope.book).toEqual(arr);
expect(scope.book).not.toEqual(undefined);
Thanks everyone!
source to share
You must first broadcast to $rootScope
, after which you can get it to $scope
. Now for testing. I am assuming you want to include the real request in your API via bookService
and $http
. It might be scoffing, but I'll focus on the real challenge. Let me know if you need a taunt.
You will need to do multiple injections / instances before the actual test:
- Initialize application
- Entering
$controller
,$rootScope
,$httpBackend
andbookService
- Create scopes for firstController and SecondController and store them in a variable
- Store
bookService
and$httpBackend
in variables - Create controller settings and save them
Then in the actual test, you have to tell $httpBackend
what to do when it caches the request for books (or books). Construct $httpBackend.whenGET("/api/books/1").passThrough();
will pass the request from the url "/api/books/1"
to the server. Then you need to set the property selectedRows
to firstScope
so that it fulfills the condition in the function selectGridRow
in your firstCtrl
.
Now you can call the function selectGridRow
to invoke the broadcast and API call. But you have to wrap it in a function runs
for Jasmine to recognize it as an asynchronous call and wait for it to complete. Waiting is defined in the call waitsFor
. It will wait for it to receive the book and it waits for a maximum of 5000ms, then the test will be marked as a failure.
The last step is to check the expected result. We don't need to validate anymore undefined
as the test won't get here anyway. The check must be wrapped in a call again runs
so that it can be executed after a successful "wait".
Here's the complete code:
describe("Broadcast between controllers", function () {
beforeEach(module('app')); //app initialization
var firstScope;
var secondScope;
var bookService;
var $httpBackend;
var firstController;
var secondController;
beforeEach(inject(function ($controller, $rootScope, _bookService_, _$httpBackend_) {
firstScope = $rootScope.$new();
secondScope = $rootScope.$new();
bookService = _bookService_;
$httpBackend = _$httpBackend_;
firstController = $controller('firstCtrl', { $scope: firstScope });
secondController = $controller('secondCtrl', { $scope: firstScope, bookService: bookService });
}));
it("should work", function () {
$httpBackend.whenGET("/api/books/1").passThrough();
firstScope.selectedRows = [{ id: 1, total: 1000 }];
secondScope.book = null;
runs(function () {
firstScope.selectGridRow();
});
waitsFor(function () {
return secondScope.book != null;
}, "Data not received in expected time", 5000);
runs(function () {
expect(secondScope.book[0].id).toEqual(1);
});
});
});
source to share