So I have this delete function that removes a single “Product” entity inside my AngularJs controller.
angular.module('demoApp').controller('ProductManageCtrl', function ($scope, Product, $window, errorMgr) {
//...more code here for loading data
$scope.deleteProduct = function (product) {
var confirm = $window.confirm('Are you sure you want to delete "' + product.title + '"?');
if (!confirm) {
return false;
}
Product.delete({ id: product._id }, function success() {
//code for delete success here....
}, errorMgr.catch('An error occurred on deleting product.'));
};
//listen for exceptions
errorMgr.handleError($scope);
});
Focusing on the $scope.deleteProduct function inside the controller, user will be ask to confirm his/her action ( by showing a native confirm dialog box ) before the delete process goes through. If the user confirms true, the product will be deleted and if vice versa, the product won’t get deleted. Check-out the screenshot below.
My unit test should mimic the confirm dialog’s logic for both scenarios. First if the user doesn’t confirm to delete, our unit test should verify that Product.delete function isn’t called/activated. And conversely, unit test should assert that Product.delete function is fired.
Using sinon.js testing library, I can stub $window.confirm and control it’s confirm function behavior. Lastly, I need to create a spy for the Product’s delete function to report if it’s fired or not.
describe('ProductManageCtrl', function () {
var productDeleteSpy, mockWindowService, scope;
beforeEach(inject(function ($rootScope, $controller, Product) {
scope = $rootScope.$new();
//mock the window confirm
//with this I can control the confirm function to return true or false
mockWindowService = sinon.stub({
confirm: function () {
}
});
//create a spy on Product's delete function
productDeleteSpy = sinon.spy(Product, 'delete');
controller = $controller('ProductManageCtrl', {
$scope: scope,
Product: Product,
$window: mockWindowService
});
//some code here to load data on test
}));
Now, I can start writing my test assertions. For the scenario when the user confirms the dialog box to delete:
it('should delete product when user confirmed', function () {
//set the confirm to return true
mockWindowService.confirm.returns(true);
scope.deleteProduct(mockProduct);
assert(mockWindowService.confirm.calledOnce);
assert(productDeleteSpy.withArgs({ id: mockProduct._id }).calledOnce);
});
And when the user doesn’t confirm or cancel the deletion process:
it('should not delete product when user do not confirm', function () {
//set the confirm to return false
mockWindowService.confirm.returns(false);
scope.deleteProduct(mockProduct);
assert(productDeleteSpy.notCalled);
});
Thanks for reading. :)